Java中,流是一种有序的字节序列,能够有任意的长度。从应用流向目的地称为输出流,从目的地流向应用称为输入流。java
Java的java.io
包中囊括了整个流的家族,输出流和输入流的谱系以下所示:设计模式
InputStream和OutputStream分别是输入输出流的顶级抽象父类,只定义了一些抽象方法供子类实现。数组
在输出流OutputStream中,若是你须要向一个输出流写入数据,能够调用void write(int b)
方法,这个方法会将b的低八位写入流中,高24位将会被自动忽略。若是想要批量写入数据呢,那么能够调用void write(byte[] b)
方法将一个字节数组的内容所有写入流中,同时还有void write(byte[] b, int off, int len)
可让你指定从哪里写入多少数据。
若是你但愿你向流中写入的数据可以尽快地输送到目的地,好比说文件,那么能够在写入数据后,调用flush()
方法将当前输出流刷到操做系统层面的缓冲区中。不过须要注意的是,此方法并不保证数据立马就能刷到实际的物理目的地(好比说存储)。
使用完流后应该调用其close()
方法将流关闭,流关闭时,将会先flush,后关闭。ide
在输入流InputStream中,能够经过int read()
方法来从流中读取一个字节,批量读取字节能够经过int read(byte[] b)
或者int read(byte[] b, int off, int len)
来实现,这两个方法的返回值为实际读取到的字节数。若是须要重复读取流中某段数据,能够在读取以前先使用void mark(int readlimit)
方法在当前位置作一个记号,以后经过void reset()
方法返回到以前作标记的位置,不过在作这些标记操做以前,须要先经过boolean markSupported()
方法来肯定该流是否支持标记。若是对某些可预知的数据不感兴趣,可使用long skip(long n)
来调过一些流中的一些数据。性能
使用完流,不管是输入仍是输出流,都要调用其close()
方法对其进行关闭。this
装饰器模式(Decorator Pattern)容许向一个现有的对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,它是做为现有的类的一个包装。spa
这种设计模式建立了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能。操作系统
以InputStream为例,它是一个抽象类:设计
public abstract class InputStream implements Closeable { ... ... }
并定义有抽象方法3d
public abstract int read() throws IOException;
该抽象方法由具体的子类去实现,经过InputStream的族谱图能够看到,直接继承了InputStream,而且提供某一特定功能的子类有:
ByteArrayInputStream
FileInputStream
ObjectInputStream
PipedInputStream
SequenceInputStream
StringBufferInputStream
这些子类都具备特定的功能,好比说,FileInputStream表明一个文件输入流并提供读取文件内容的功能,ObjectInputStream提供了对象反序列化的功能。
InputStream这个抽象类有一个子类与上述其它子类很是不一样,这个子类就是FilterInputStream,可参见上图中的InputStream族谱图。
翻开FilterInputStream的代码,咱们能够看到,它内部又维护了一个InputStream的成员对象,而且它的全部方法,都是调用这个成员对象的同名方法。
换句话说,FilterInputStream它什么事都不作。就是把调用委托给内部的InputStream成员对象。以下所示:
public class FilterInputStream extends InputStream { protected volatile InputStream in; protected FilterInputStream(InputStream in) { this.in = in; } public int read() throws IOException { return in.read(); } public int read(byte b[]) throws IOException { return read(b, 0, b.length); } public int read(byte b[], int off, int len) throws IOException { return in.read(b, off, len); } public long skip(long n) throws IOException { return in.skip(n); } public int available() throws IOException { return in.available(); } public void close() throws IOException { in.close(); } public synchronized void mark(int readlimit) { in.mark(readlimit); } public synchronized void reset() throws IOException { in.reset(); } public boolean markSupported() { return in.markSupported(); }
FilterInputStream的又有其子类,分别是:
BufferedInputStream
DataInputStream
LineNumberInputStream
PushbackInputStream
虽然从上面代码看FilterInputStream并无作什么有卵用的事,可是它的子类可不一样了,以BufferedInputStream为例,这个类提供了提早读取数据的功能,也就是缓冲的功能。能够看看它的read方法:
public synchronized int read() throws IOException { if (pos >= count) { fill(); if (pos >= count) return -1; } return getBufIfOpen()[pos++] & 0xff; }
能够看到,当pos>=count时,意即须要提早缓冲一些数据的时候到了,那么就会调用fill()将缓冲区加满,以便后续读取。因为本文只讨论io流的装饰器模式,因此关于具体实现细节将不会展开讨论,好比本文不会讨论fill()方法是如何实现的,在这里能够先将它当作一个黑盒子。
从这里能够开始感觉到,BufferedInputStream就是一个装饰者,它能为一个本来没有缓冲功能的InputStream添加上缓冲的功能。
好比咱们经常使用的FileInputStream,它并无缓冲功能,咱们每次调用read,都会向操做系统发起调用索要数据。假如咱们经过BufferedInputStream来装饰它,那么每次调用read,会预先向操做系统多拿一些数据,这样就不知不觉中提升了程序的性能。如如下代码所示:
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(new File("/home/user/abc.txt")));
同理,对于其它的FilterInputStream的子类,其做用也是同样的,那就是装饰一个InputStream,为它添加它本来不具备的功能。OutputStream以及家眷对于装饰器模式的体现,也以此类推。
JDK中的io流的设计是设计模式中装饰器模式的一个经典示范,若是细心发现,JDK中还有许多其它设计模式的体现,好比说监听者模式等等。