欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Java中的stream流的概念解析及实际运用总结

程序员文章站 2024-03-12 17:21:50
流是字节序列的抽象概念。 文件是数据的静态存储形式,而流是指数据传输时的形态。 流类分为两个大类:节点流类和过滤流类(也叫处理流类)。 程序用于直接操作目标设备所对应...

流是字节序列的抽象概念。
文件是数据的静态存储形式,而流是指数据传输时的形态。
流类分为两个大类:节点流类和过滤流类(也叫处理流类)。
程序用于直接操作目标设备所对应的类叫节点流类,程序也可以通过一个间接流类去调用节点流类,以达到更加灵活方便地读取各种类型的数据,这个间接流类就是过滤流类(也叫处理流类),或者称为包装类。
包装类的调用过程如下图:

Java中的stream流的概念解析及实际运用总结

流分类的关系
不管流的分类是多么的丰富和复杂,其根源来自于四个基本的类。这个四个类的关系如下:

字节流 字符流
输入流 inputstream reader
输出流 outputstream writer

java内用 unicode 编码存储字符,字符流处理类负责将外部的其他编码的字符流和java内 unicode 字符流之间的转换。而类inputstreamreader 和outputstreamwriter处理字符流和字节流的转换。字符流(一次可以处理一个缓冲区)一次操作比字节流(一次一个字节)效率高。

inputstream

Java中的stream流的概念解析及实际运用总结

由于inputstream和outputstream是abstact类,所以它们还不能表明具体对应哪种io设备。它们下面有许多子类,包括网络、管道、内存、文件等具体的io设备,实际程序中使用的它们的各种子类对象。
注:我们将节点流类所对应的io源和目标称为流节点(node)。
注意:将a文件的内容写入b文件,程序对a文件的操作所用的是输出类还是输入类这个问题。输入输出类是相对程序而言的,而不是代表文件的,所以我们应该创建一个输入类来完成对a文件的操作,创建一个输出类来完成对b文件的操作。

outputstream

Java中的stream流的概念解析及实际运用总结

以字符为导向的 stream reader/writer
以 unicode 字符为导向的 stream ,表示以 unicode 字符为单位从 stream 中读取或往 stream 中写入信息。同样,reader/writer也为abstact类。

reader
Java中的stream流的概念解析及实际运用总结

writer

Java中的stream流的概念解析及实际运用总结

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的流很方便也很复杂。复杂就复杂在实现一个功能往往需要多个类,而且有多种组合的办法。尚需继续在实践中总结。