java学习脚印:I/O 流概观(OverView)

java学习脚印:I/O 流概观(OverView)

写在前面

           java为IO提供了两个包java.io,java.nio包,其中包括很多的类,让初学者眼花缭乱,不知道如何选择,这样就不能发挥两个包的最大作用了。这里旨在从宏观上把握,整理了一个关于java IO流的一个框架,以期对后续学习有所指引。文中翻译或者引用的文章均列在参考资料部分。



1.什么是I/O流?

        本段内容翻译自[1]。

    I/O流代表了输入源或者输入目的地。一个流可以表示各种各样的源和目的地,例如磁盘,其他设备,网络,其他程序以及内存数组等等。

     流支持各种数据,包括最简单的字节,基本数据类型,本地化的字符和对象。一些流仅仅传递数据,另一些流以有用的形式对数据进行加工或者转化。

     对于使用流的应用程序而言,不管流内部如何工作,他们都是一个同样的简单模型,那就是:流就是一个数据序列。

一个程序使用输入流来从数据源一个条目一个条目地读取数据,如下图(引用自[2])所示:

java学习脚印:I/O 流概观(OverView)_第1张图片

一个程序使用输出流向目的地一个条目一个条目地写入数据,如下图(引用自[2])所示:


java学习脚印:I/O 流概观(OverView)_第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]):




3.流的层次关系

java中的流大方向上分为两个层次,一个层次用于处理字节输入输出;另一个层次处理字符的输入和输出。另外I/O包中还定义了一些接口。(参考自[5])

这里记住Java命名的惯例,凡是以InputStream或OutputStream结尾的类型均为字节流,凡是以Reader或Writer结尾的均为字符流。


3.1  字节流

字节输入的类间关系图如下所示:

java学习脚印:I/O 流概观(OverView)_第3张图片


字节输出的类间关系图如下所示:

java学习脚印:I/O 流概观(OverView)_第4张图片

关于字节流,可以小结一下(参考自[7])

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()方法提供了字符输入输出流。

3.2 字符流

字符输入流的类间关系如下图所示:



字符输出的类间关系如下图所示:



关于字符流可小结一下(参考自[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将字符流转变为字节流;


3.3 I/O包中的接口

I/O包中的接口关系如下图所示:


java学习脚印:I/O 流概观(OverView)_第5张图片



3.4 字节与字符的转化接口

java.io包中提供了一些类允许你在字符和字节流之间进行转换。使用InputStreamReader类,你可以将字节流转化为字符流;使用OutputStreamWriter类你可以将字符流转换为字节流。

字节流转换为字符流,相关的类结构如下图所示(参考自[7]):

java学习脚印:I/O 流概观(OverView)_第6张图片



字符流转换为字节流,相关的类结构如下图所示(参考自[8]):



4.java IO设计原则

         java语言的I/O库是对各种常见的数据源和目的地以及处理过程的抽象化。要理解java I/O 这个庞大而复杂的库,关键是掌握两个对称性和两个设计模式(参考自[6])。

4.1 java I/O库具有两个对称性

java I/O库具有两个对称性,它们分别是:
     1) 输入-输出对称:比如InputStream 和OutputStream 各自占据Byte流的输入和输出的两个平行的等级结构的根部;而Reader和Writer各自占据Char流的输入和输出的两个平行的等级结构的根部。
     2) byte-char对称:InputStream和Reader的子类分别负责byte和插入流的输入;OutputStream和Writer的子类分别负责byte和Char流的输出,它们分别形成平行的等级结构。

4.2 java I/O库的两个设计模式


      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数据,这就是适配器模式的应用。

5.参考资料

[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/

你可能感兴趣的:(java学习脚印:I/O 流概观(OverView))