Java中的stream流的概念解析及实际运用总结
作者:pizzq 发布时间:2022-06-10 23:19:10
流是字节序列的抽象概念。
文件是数据的静态存储形式,而流是指数据传输时的形态。
流类分为两个大类:节点流类和过滤流类(也叫处理流类)。
程序用于直接操作目标设备所对应的类叫节点流类,程序也可以通过一个间接流类去调用节点流类,以达到更加灵活方便地读取各种类型的数据,这个间接流类就是过滤流类(也叫处理流类),或者称为包装类。
包装类的调用过程如下图:
流分类的关系
不管流的分类是多么的丰富和复杂,其根源来自于四个基本的类。这个四个类的关系如下:
字节流 | 字符流 | |
输入流 | InputStream | Reader |
输出流 | OutputStream | Writer |
Java内用 Unicode 编码存储字符,字符流处理类负责将外部的其他编码的字符流和java内 Unicode 字符流之间的转换。而类InputStreamReader 和OutputStreamWriter处理字符流和字节流的转换。字符流(一次可以处理一个缓冲区)一次操作比字节流(一次一个字节)效率高。
InputStream
由于InputStream和OutputStream是abstact类,所以它们还不能表明具体对应哪种IO设备。它们下面有许多子类,包括网络、管道、内存、文件等具体的IO设备,实际程序中使用的它们的各种子类对象。
注:我们将节点流类所对应的IO源和目标称为流节点(Node)。
注意:将A文件的内容写入B文件,程序对A文件的操作所用的是输出类还是输入类这个问题。输入输出类是相对程序而言的,而不是代表文件的,所以我们应该创建一个输入类来完成对A文件的操作,创建一个输出类来完成对B文件的操作。
OutputStream
以字符为导向的 stream Reader/Writer
以 Unicode 字符为导向的 stream ,表示以 Unicode 字符为单位从 stream 中读取或往 stream 中写入信息。同样,Reader/Writer也为abstact类。
Reader
Writer
IO程序代码的复用:
平时写代码用-1来作为键盘输入的结束,在写的函数中不直接使用System.in,只是在调用该函数时,将System.in作为参数传递进去,这样,我们以后要从某个文件中读取数据,来代替手工键盘输入时,我们可以直接使用这个函数,程序就不用做太多的修改了,达到以不变应万变的效果。
字节流和字符流的相互转换
InputStreamReader和OutputStreamReader:把一个以字节为导向的stream转换成一个以字符为导向的stream。
InputStreamReader类是从字节流到字符流的桥梁:它读入字节,并根据指定的编码方式,将之转换为字符流。
使用的编码方式可能由名称指定,或平台可接受的缺省编码方式。
InputStreamReader的read()方法之一的每次调用,可能促使从基本字节输入流中读取一个或多个字节。
为了达到更高效率,考虑用BufferedReader封装InputStreamReader,
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
Java流使用的一点总结
最经工作中碰到不少Java流的使用,总结如下:
1. 生成Zip格式,遇到的是要在一个Servlet中生成Zip文件,输出到web 客户端,直接下载。
response.setContentType("application/zip");
response.addHeader("Content-Disposition", "attachment;filename=/"xxx.zip/"");
ZipOutputStream out = new ZipOutputStream(response.getOutputStream())
for()
{
ZipEntry entry = new ZipEntry("aa" + i ".dat");
out.putNewEntry(entry);
bytes[] bt = s.getBytes();
out.writeBytes(bt, 0, bt.length());
out.closeEntry();
}
out.flush();
out.close();
ZipOutputStream 继承自 java.io.FilterOutputStream. 因此真正的写操作是通过参数OutputStream out去写的。
其 void write(byte[] b, int off, int len) 最终调用了 out.write(b, off, len);
如果要生成一个zip文件,构造时就这样写 new ZipOutputStream(new FileOutputStream(path));
2. 类似的写XML.
XMLWriter writer = new XMLWriter(new FileOutputStream(path), formater)
writer.write(doc).道理和上面类似
3. 写文本文件,追加。
PrintStream ps = new PrintStream(new FileOutputStream(path, true), "utf-8")
ps.println(s); // 能写boolean、int等各种类型。
PrintSteam同样继承自FilterOutputStream
其内部使用一个OutputStreamWriter的对象textOut来写。例如write(String s)最终调用到textOut.write(s);
这里涉及到编码的问题。其参数里的"utf-8"最终传递到OutputStream。
OutputStream是一个字符流和字节流之间的桥梁。
因此其提供了write(char[] cbuf, int off, int len) 和 write(String str, int off, int len) 用来写字符和字符串。
OutputStream内部又通过一个StreamEncoder对象来序列化字符和字符串。
4. 写出到socket。
DataOutputStream out = new DataOutputStream(socket.getOutputStream());
out.writeBytes(bt);
out.writeBoolean(boolean v) ;
DataOutputStream同样是一个自FilterOutputStream.
5. 从文本中读取
BufferedReader reader = new BufferedReader(new FileReader(path));
reader.readLine();
BufferedReader的模式和上面的Filter模式一样,其内部存储一个Reader对象为参数传进来并用来实际读取的对象。
BufferedReader对应java 1.0的类就是BufferedInputStream,是一个FilterInputStream。
6. 从Socket中读取
BufferedInputStream is = new BufferedInputStream(socket.getInputStream());
is.read(bt, 0, bt.length());
总结:
基类Stream系列是InputStream和OutputStream,他们是抽象类,要求的方法只有(以Output为例)
void write(int b) throws IOException;
void write(byte b[]) throws IOException
void write(byte b[], int off, int len)
其最基本的只是字节操作。第1个方法看似写一个整数,其实只写一个字节(最低八个bit)。其子类分两个系列,一个是直接操作输出设备的,我们上面碰到的有文件(FileOutputStream)和Servlet输出(ServletOutputStream)。其他常用的还有一个 ByteArrayOutputStream,是直接在内存里操作的。
再就是FilterOutputStream系列了,都是接收一个OutputStream对象座位参数,真正的写操作通过该对象去完成。例如ZipOutputStream,其本身只负责生成压缩格式的数据,至于这些数据是写到文件、内存、还是servletResponse,由输入的参数确定。这就是装饰器模式。
Filter系列常用的有PrintStream(提供了print,println,write(boolean[int, char, string])各种操作,最终利用out.write方法以写字节的方式写进去。
还有DataOutputStream,其提供了writeByte/writeBoolean/writeDouble/writeLong/wiretUTF等方法。
还有就是socket/zip等不常用的。
Java的流很方便也很复杂。复杂就复杂在实现一个功能往往需要多个类,而且有多种组合的办法。尚需继续在实践中总结。
猜你喜欢
- 1、普通用户与系统管理员用户的权限要有严格的区分。如果一个普通用户在使用查询语句中嵌入另一个Drop Table语句,那么是否允许
- servlet实现文件上传,预览,下载和删除,供大家参考,具体内容如下一、准备工作:1.1 文件上传插件:uploadify;1.2 文件上
- 前言在实际生活中,地图是我们经常使用的一种工具,通常我们会用它进行导航,输入一个出发城市,输入一个目的地城市,就可以把路线规划好,而在规划好
- 这是主要使用到的jar 文件是:spring mvc +apache common-fileuplad第一步:web.xml 文件。【重点是
- 本文实例讲述了Java类加载器和类加载机制。分享给大家供大家参考,具体如下:一 点睛1 类加载器负责将.class文件(可能在磁盘上,也可能
- 1.情景展示java发送get请求、post请求(form表单、json数据)至另一服务器;可设置HTTP请求头部信息,可以接收服务器返回c
- 简介我们在开发web应用的时候,有时候为了适应浏览器大小的调整,需要动态对页面的组件进行位置的调整。这时候就会用到flow layout,也
- jsoup 是一款 Java 的 HTML 解析器,可直接解析某个 URL 地址、HTML 文本内容。它提供了一套非常省力的 API,可通过
- 图像滤波在opencv中可以有多种实现形式自定义滤波如使用3×3的掩模:对图像进行处理.使用函数filter2D()实现#include&l
- 本文实例为大家分享了java实现简单斗地主的具体代码,供大家参考,具体内容如下第一种方法 /** * @param args */ /**
- 1. 父工程构建1.1 Maven项目搭建环境版本JDK1.8Maven3.6+Maven模板maven-archetype-size删除父
- 您已经看到很多包含视频内容的应用程序,比如带有视频教程的食谱应用程序、电影应用程序和体育相关的应用程序。您是否想知道如何将视频内容添加到您的
- 目录Spring事件驱动源码实战在项目实际开发过程中,我们有很多这样的业务场景:一个事务中处理完一个业务逻辑后需要跟着处理另外一个业务逻辑,
- 本文实例讲述了java实现日期拆分的方法。分享给大家供大家参考。具体如下:如:计算6-1至6-5之间的日期天数及具体日期,预期的结果是得到:
- 介绍Java中的建造者模式是一种创建型设计模式,它的主要目的是为了通过一系列简单的步骤构建复杂的对象,允许创建复杂对象的不同表示形式,同时隐
- 前言本文主要给大家介绍的是关于Java对xls文件进行读写操作的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍:wi
- 1.super介绍我们可以通过super关键字来实现对父类成员的访问,用来引用当前对象的父类。用于访问父类的属性,方法,构造器2.super
- 这篇文章主要介绍了Spring如何在一个事务中开启另一个事务,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需
- 这篇文章主要介绍了Java反射通过Getter方法获取对象VO的属性值过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定
- 初步探索首先我们要了解equals方法是什么,hashcode方法是什么。equals方法equals 是java的obejct类的一个方法