写在前面
java为IO提供了两个包java.io,java.nio包,其中包括很多的类,让初学者眼花缭乱,不知道如何选择,这样就不能发挥两个包的最大作用了。这里旨在从宏观上把握,整理了一个关于java IO流的一个框架,以期对后续学习有所指引。文中翻译或者引用的文章均列在参考资料部分。
本段内容翻译自[1]。
I/O流代表了输入源或者输入目的地。一个流可以表示各种各样的源和目的地,例如磁盘,其他设备,网络,其他程序以及内存数组等等。
流支持各种数据,包括最简单的字节,基本数据类型,本地化的字符和对象。一些流仅仅传递数据,另一些流以有用的形式对数据进行加工或者转化。
对于使用流的应用程序而言,不管流内部如何工作,他们都是一个同样的简单模型,那就是:流就是一个数据序列。
一个程序使用输入流来从数据源一个条目一个条目地读取数据,如下图(引用自[2])所示:
一个程序使用输出流向目的地一个条目一个条目地写入数据,如下图(引用自[2])所示:
根据流的传输特性和与数据源的关联特点,可以将流分为三类(参考自[3][4]),下面逐一讲述。
2.1 流的方向划分——输入流(Input Stream)和输出流(Output Stream)
根据流的流动方向可以分为输入流(Input Stream)和输出流(Output Stream).
输入流只能从中读取数据而不能写入,输出流正好与其相反。
java I/O为输入和输出分别实现了相应的类,稍后将介绍。
2.2 传输单位划分——字符流(Character Stream)和字节流(Byte Stream)
根据流传输数据单位可以划分为,字符流(Character Stream)和字节流(Byte Stream).
字节流以字节(8 bits)为单位进行数据传输,每次传送一个或多个字节;字符流以字符(16 bits)为单位进行数据传输,每次传送一个或多个字符.
java I/O包为字符流和字节流分别实现了两套类来完成数据操作,稍后将介绍。
2.3 流与数据源的关联特点划分——节点流(Node Stream)和处理流(Processing Stream)
根据数据流所关联的是数据源还是其他数据流,可划分为节点流(Node Stream)和处理流(Processing Stream)。
节点流,直接连接到数据源,一般用于直接用于直接从指定的位置进行读/写操作,例如磁盘文件、内存区域、网络连接等,其中一般只提供一些基本的读写操作方法,功能比较单一。关于节点流和处理流,可参看下面的示意图(引用自[4]):
java中的流大方向上分为两个层次,一个层次用于处理字节输入输出;另一个层次处理字符的输入和输出。另外I/O包中还定义了一些接口。(参考自[5])。
这里记住Java命名的惯例,凡是以InputStream或OutputStream结尾的类型均为字节流,凡是以Reader或Writer结尾的均为字符流。
字节输入流的类间关系图如下所示:
字节输出流的类间关系图如下所示:
1) InputStream /OutputStream是所有的输入/出字节流的父类,它们都是一个抽象类。
2) 按处理数据介质区分:
ByteArrayInputStream/ByteArrayOutputStream是像字节数组输入/输出的字节流类;
FileInputStream/ FileOutputStream是像本地文件输入/输出的字节流类 是三种基本的介质流;
PipedInputStream/ PipedOutputStream 是从与其它线程共用的管道中读取或者写入数据;
3) 按处理数据类型区分:
InputStream和OutputStream,所操作的基本单元就是字节,每次读取和写入单个字节或是字节数组;
DataInputStream和DataOutputStream,支持以二进制形式操纵的原始数据类型,如byte,int等。
ObjectInputStream和ObjectOutputStream,支持以二进制形式操纵的基本数据类型和对象类型。
4) 装饰器流
所有FilterInputStream/ FilterOutputStream的子类都是装饰流(装饰器模式的主角)。 例如PushbackInputStream支持回退操作,将读取的一个字节重新送回,下次可继续读取;InflaterInputStream用来支持解压缩数据。
5)标准输入输出流
java提供了标准输入输出流,System.in,System.out和System.err,他们都是字节流。其中System.out and System.err被定义为PrintStream对象,他们虽然是字节流,但是它利用内部字符流对象模拟了字符流的大部分特性;而System.in它没有字符流特性,要想将他当做字符流使用,可以使用如下代码:
InputStreamReader cin = new InputStreamReader(System.in);
同时,另一种替代标准输入输出流的是Console类,这是一个final类,Console类通过reader()和writer()方法提供了字符输入输出流。
字符输入流的类间关系如下图所示:
字符输出流的类间关系如下图所示:
关于字符流可小结一下(参考自[7]):
1) Reader/Writer 是所有的输入/出字符流的父类,它是一个抽象类。
2) 按处理数据介质区分:
CharReader/CharArrayWriter 向Char 数组中输入/出数据;
StringReader/StringWriter 向String中输入/出数据。
FileReader/FileWriter 是向文件输入/出数据。
PipedReader/PipedWriter 是从与其它线程共用的管道中读取/写入数据。
PrintWriter 以格式化方式写入字符串到字符输出流。
3) 装饰器流
BufferedReader/BufferedWriter 很明显就是一个装饰器,它和其子类负责装饰其它Reader/Writer 对象,提供缓冲功能。
FilterReader 是所有自定义具体装饰流的父类,其子类PushbackReader支持回退操作。
InputStreamReader/OutputStreamWriter 是一个连接字节流和字符流的桥梁,InputStreamReader它将字节流转变为字符流,OutputStreamWriter将字符流转变为字节流;
I/O包中的接口关系如下图所示:
java.io包中提供了一些类允许你在字符和字节流之间进行转换。使用InputStreamReader类,你可以将字节流转化为字符流;使用OutputStreamWriter类你可以将字符流转换为字节流。
字符流转换为字节流,相关的类结构如下图所示(参考自[8]):
java语言的I/O库是对各种常见的数据源和目的地以及处理过程的抽象化。要理解java I/O 这个庞大而复杂的库,关键是掌握两个对称性和两个设计模式(参考自[6])。
java I/O库具有两个对称性,它们分别是:
1) 输入-输出对称:比如InputStream 和OutputStream 各自占据Byte流的输入和输出的两个平行的等级结构的根部;而Reader和Writer各自占据Char流的输入和输出的两个平行的等级结构的根部。
2) byte-char对称:InputStream和Reader的子类分别负责byte和插入流的输入;OutputStream和Writer的子类分别负责byte和Char流的输出,它们分别形成平行的等级结构。
java I/O库的总体设计是符合装饰模式和适配器模式的。如前所述,这个库中处理流的类叫流类。
装饰模式:在由InputStream、OutputStream、Reader和Writer代表的等级结构内部,有一些流处理器可以对另一些流处理器起到装饰作用,形成新的、具有改善了的功能的流处理器。
例如代码:
InputStream in = new BufferedInputStream(new FileInputStream("test.txt"));
BufferedInputStream封装了FileInputStream提供了缓冲功能,这就是一个装饰模式。
适配器模式:在由InputStream、OutputStream、Reader和Writer代表的等级结构内部,有一些流处理器是对其他类型的流处理器的适配。这就是适配器的应用。
例如,在前面提到的InputStreamReader类,它起到了从byte流到char流的一个桥梁作用,它读入byte数据并根据指定的编码将之翻译成char数据,这就是适配器模式的应用。
[1]: http://docs.oracle.com/javase/tutorial/essential/io/streams.html
[2]: http://blog.stikom.edu/rachmawati/files/2012/11/PBO_07_IOStream.pdf
[3]: http://fehly.iteye.com/blog/658998
[4]: http://www.oseye.net/user/kevin/blog/169
[5]:《java核心技术:卷二》 机械工业出版社 第八版
[6]:java I/O库中设计模式的应用 http://my.oschina.net/gao0516/blog/136103
[7]:Java IO流学习总结 http://www.cnblogs.com/oubo/archive/2012/01/06/2394638.html
[8]: 深入分析 Java I/O 的工作机制 http://www.ibm.com/developerworks/cn/java/j-lo-javaio/