一、简单介绍JAVA I/O
JAVA采用流的机制来实现输入/输出,流就是数据的有序排列,而流可以是从某个源(称为流源或Source of Stream)出来,到某个目的地(称为流汇或Sink of Stream)去的。由流的方向,可以分成输入流和输出流,一个程序从输入流读取数据向输出流写数据。
如,一个程序可以用FileInputStream类从一个磁盘文件读取数据,如下图所示:
像FileInputStream这样的处理器叫做流处理器,它就像流的管道一样,从一个流源吸入某种类型的数据,并输出某种类型的数据。上面这种示意图叫做流的管道图。
在实际应用这种机制并不没有太大的用处,程序需要写出地通常是非常结构化的信息,因此这些byte类型的数据实际上是一些数值,文字,源代码等。Java的I/O库提供了一个称做链接(Chaining)的机制,可以将一个流处理器跟另一个流处理器首尾相接,以其中之一的输出为输入,形成一个流管道的链接。
例如,DataInputStream流处理器可以把FileInputStream流对象的输出当作输入,将Byte类型的数据转换成Java的原始类型和String类型的数据。如下图所示:
流处理器处理的流必定有流源,如果将流类所处理的流源分类的话,基本可以分成两类:
①数组、String、File等,这种叫原始流源;
②同样类型的流用作链接流的源,叫链接流源。
二、Java I/O库的设计原则
要理解Java I/O这个庞大而复杂的库,关键是要掌握两个对称性跟两个设计模式模式:
1.Java I/O库具有两个对称性,它们分别是:
①输入-输出对称性,比如InputStream和OutputStream各自占据Byte流的输入与输出的两个平行的等级结构的根部。而Reader和Writer各自占据Char流的输入与输出的两个平行的等级结构的根部。
②byte-char对称,InputStream和Reader的子类分别负责Byte和Char流的输入;OutputStream和Writer的子类分别负责Byte和Char流的输出,它们分别形成平行的等级结构。
Java I/O库的两个设计模式:
2.Java的I/O库总体设计是符合装饰者模式(Decorator)跟适配器模式(Adapter)的:
①装饰者模式:在由InputStream,OutputStream,Reader和Writer代表的等级结构内部,有一些流处理器可以对另一些流处理器起到装饰作用,形成新的,具有改善了的功能的流处理器。装饰者模式是Java I/O库的整体设计模式。
②适配器模式:在由InputStream,OutputStream,Reader和Writer代表的等级结构内部,有一些流处理器是对其它类型的流源的适配,这就是适配器模式的应用。
三、装饰模式的应用
我们知道Java I/O库需要很多性能的各种组合,如果说这些性能的组合是通过继承方式来实现的话,那么每一种组合都需要一个类,这样就会出现大量重复性问题的出现,从而使类数目“爆炸”。而如果采用装饰模式,那么不仅类的数目大减少了,性能的重复也可以减至到最少。
我们来看InputStream类型中的装饰模式:
InputStream有七个直接的具体子类,有四个属于FilterInputStream的具体子类,如下图所示:
1.InputStream中的原始流处理器
原始流处理器接受一个Byte数组对象、String对象、FileDiscriptor对象或者不同类型的流源对象,上面的图中包括四种原始流处理器:
ByteArrayInputStream:为多线程的通信提供缓冲区操作功能,接收一个Byte数组作为流的源。
FileInputStream:建立一个与文件有关的输入流。接收一个File对象作为流的源。
PipedInputStream:可以与PipedOutputStream配合使用,用于读入一个数据管道的数据,接收一个PipedOutputStream作为源。
StringBufferInputStream:将一个字符串缓冲区转换为一个输入流。接收一个String对象作为流的源。(JDK帮助文档上说明:已过时。此类未能正确地将字符转换为字节。从JDK1.1开始,从字符串创建流的首选方法是通过StringReader类进行创建。只有字符串中每个字符的低八位可以由此类使用。)
2.InputStream中的链接流处理器
所谓链接流处理器,就是可以接收另一个流对象作为源,并对之进行功能扩展的类。InputStream类型的链接处理器包括以下几种,它们都接收另一个InputStream对象作为流源。
①FilterInputStream称为过滤输入流,它将另一个输入流作为流源。这个类的子类包括以下几种:
BufferedInputStream:用来从硬盘将数据读入到一个内存缓冲区中,并从缓冲区提供数据。
DataInputStream:提供基于多字节的读取方法,可以读取原始类型的数据。
LineNumberInputStream:提供带有行计数功能的过滤输入流。
PushbackInputStream:提供特殊的功能,可以将已经读取的字节“推回”到输入流中。
②ObjectInputStream可以将使用ObjectInputStream串行化的原始数据类型和对象重新并行化。
③SeqcueneInputStream可以将两个已有的输入流连接起来,形成一个输入流,从而将多个输入流排列构成一个输入流序列。
抽象结构图
按照上面的这种原始流处理器和链接流处理器的划分,可以用下面的结构图来描述它们之间的关系:
3.装饰模式
FilterStream的源码:
public class FilterInputStream extends InputStream{
protected InputStream in;
protected FilterInputStream(InputStream in){
this.in = in;
}
}
FilterInputStream继承了InputStream,也引用了InputStream,而它有四个子类,这就是所谓的Decorator模式。
链接流对象接收一个原始流对象或者另外一个链接流对象作为流源;另一方面他们对流源的内部工作方法做了相应的改变,这种改变是装饰模式所要达到的目的。
BufferedInputStream“装饰”了InputStream的内部工作方式,使得流的读入操作使用了缓冲机制。在使用了缓冲机制后,不会对每一次的流读入操作都产生一个物理的读盘动作,从而提高了程序的效率,在汲及到物理流的读入时,都应当使用这个装饰流类;DataInputStream子类读入各种不同的原始数据类型以及String类型的数据,这一点可以从它提供的各种read方法看出来。
四、适配器模式的应用
InputStream类型的原始流处理器是适配器模式的应用
1.ByteArrayInputStream是一个适配器类
ByteArrayInputStream继承了InputStream的抽象类,而封装了一个byte数组。换言之,它将一个byte数组的接口适配成InputStream流处理器的接口。
Java语言支持四种类型:Java接口,Java类,Java数组,原始类型(即int,float等)。前三种是引用类型,类和数组的实例是对象,原始类型的值不是对象。也即,Java语言的数组是像所有的其他对象一样的对象,而不管数组中所存储的元素类型是什么。这样一来的话,ByteArrayInputStream就符合适配器模式的描述,是一个对象形式的适配器类。
2. FileInputStream是一个适配器类
在FileInputStream继承了InputStrem类型,同时持有一个对FileDiscriptor的引用。这是将一个FileDiscriptor对象适配成InputStrem类型的对象形式的适配器模式。
3. StringReader是一个适配器类
StringReader类继承了Reader类型,持有一个对String对象的引用。它将String的接口适 配成Reader类型的接口。
4.从byte流到char流的适配
在Java I/O库中,使用比较频繁的要数InputStreamReader,OutputStreamWriter这两种类了,InputStreamReader是从byte输入流到char输入流的一个适配器。
转自:http://blog.csdn.net/mimicimim/article/details/1798465