Java I/O全文摘要(六)过滤流,过滤流

1.过滤流

"Filter streams are used for encryption, compression, translation, buffering, and much more."

过滤流用于加密,压缩,翻译,缓冲和其他功能。


过滤器从预先存在的流中读取数据,然后在传递到客户端程序之前,有机会改变他的数据。

可将多个流连成一条链对底层的流使用。

过滤流不仅仅移除掉你不想要的,还能增加你想要的。


2. 过滤流类

两个超级类:java.io.FilterInputStream和java.io.FilterOutputStream

public class FilterInputStream extends InputStream
public class FilterOutputStream extends OutputStream

它们都只有一个protected类型的结构体

protected FilterInputStream(InputStream in)
protected FilterOutputStream(OutputStream out)

由于结构体是保护的,所以需要采用子类实现部分功能,并提供public的结构体

它们使用一个超级类作为成员变量,然后对这个成员变量进行修饰

protected InputStream in
protected OutputStream out


其实除了构造方法,常用的是下面这些:

对于FilterInputStream:

public int  read( ) throws IOException
public int  read(byte[] data) throws IOException
public int  read(byte[] data, int offset, int length) throws IOException
public long skip(long n) throws IOException
public int  available( ) throws IOException
public void close( ) throws IOException
public void mark(int readlimit)
public void reset( ) throws IOException
public boolean markSupported( )

对于FilterOutputStream:

public void write(int b) throws IOException
public void write(byte[] data) throws IOException
public void write(byte[] data, int offset, int length) throws IOException
public void flush( ) throws IOException
public void close( ) throws IOException


所以,默认的行为只是转发相应的操作,例如:

public long skip(long n) throws IOException {
  in.skip(n);
}

以及

public void close( ) throws IOException {
  out.close( );
}

由于没有无参构造函数,所以在子类中你必须显示的调用父类的构造函数。


3. 过滤流类的子类

java.io包中包含了很多有用的过滤流子类

BufferedInputStream and BufferedOutputStream为原有的输入输出提供了缓冲字节数组,这样,再使用这个流就不必要从native方式去读取数据了。

这在很多时候能提高性能,并且运行输入流重读操作。


java.io.PrintStream允许非常简单的打印原始类型,对象和字符串字母。

使用平台默认的编码集来转化字符到字节。

System.out and System.err是最出名的java.io.PrintStream

你也可以自己实例化它。例如结合使用PrintStream to aFileOutputStream


PushbackInputStream拥有一个字节的回退缓冲,这样程序可以实现"unread"最后一个字符。

下一次读取时,这个字符将被重新读取。


ProgressMonitorInputStream将告知用户读了多少,还有多少可读。


DataInputStream and DataOutputStream将用平台独立的方式读写Java原始类型和String

(Big-endian for integer types, IEEE-754 forfloats anddoubles, a variant of UTF-8 for strings.)


ObjectInputStream andObjectOutputStream继承自DataInputStream and DataOutputStream,但它却可以像读取原始类型一样读取整个Java对象。


java.util.zip包中也包含了一些过滤流。用于压缩和解压。由于压缩和解压容易使得文件损坏,所以提供了一些校验和。


java.util.security包中包含了DigestInputStream andDigestOutputStream


JCE也提供了两个加密过滤流:CipherInputStream andCipherOutputStream


4.Buffered Streams

buffer流会读取超过所需的内容,而在需要时,可以直接从buffer中取出内容而无需再从实质的流中读取。

两个InputStream,两个OutputStream的构造方法

public BufferedInputStream(InputStream in)
public BufferedInputStream(InputStream in, int size)
public BufferedOutputStream(OutputStream out)
public BufferedOutputStream(OutputStream out, int size)

第一个参数指定了实际的流(当然,它也可能被装饰),第二个参数则是指定缓冲的大小。

没有指定则是2048,最佳实践通常取决于块的大小,小于512或者大于8192通常都不大合适。

理想情况是块的整数倍。

当然,你可能在不可靠的网络流上使用较小的缓冲。

URL u = new URL("http://java.sun.com");
BufferedInputStream bis = new BufferedInputStream(u.openStream( ), 256);

这种情况下,使用了256长度的缓冲尺寸。


5. 一个缓冲流的例子

import java.io.*;
public class BufferedStreamCopier {
  public static void main(String[] args) {
    try {
      copy(System.in, System.out);
    }
    catch (IOException ex) {
      System.err.println(ex);
    }
  }

  public static void copy(InputStream in, OutputStream out)
   throws IOException {
    BufferedInputStream 
 bin = new BufferedInputStream(in);
    BufferedOutputStream bout = new BufferedOutputStream(out);
    while (true) {
      int datum = bin.read( );
      if (datum == -1) break;
      bout.write(datum);
    }
    bout.flush( );
  }
}

copy方法1字节1字节的拷贝,通常是没有效率的,但是如果使用了缓冲流,那么拷贝工作是在内存中进行的,就会变得有效率的多了。

有意的调用了flush方法,这是因为只有在缓冲流flush或者到达缓冲满时,才会使得实质的流到达数据的终点。

因此,调用flush()是十分有必要的。


6. 缓冲输入流(BufferedInputStream)的细节

BufferedInputStream继承自InputStream,它仅仅覆盖了父类的方法,没有提供任何新的方法。

 标记(Marking)和重置 (resetting)是支持的。


在Java版本1.2及之后,两个多byte读取都是采用逐字方式读取的。

buffer和状态信息都保存在受保护的域中。

protected byte[] buf
protected int    count
protected int    pos
protected int    markpos
protected int    marklimit

其中:buf是保存缓冲的byte数组,count是buffer中的byte数量,read()返回的index是pos,标记叫做markpos,领先于mark位置的长度使得mark无效叫做marklimit。


7 缓冲输出流(BufferedOunputStream)的细节

BufferedInputStream很相似,它也有buf数组和pos表示位置

protected byte buf[]
protected int  pos

PushbackInputStream

java.io.PushbackInputStream提供了pushback缓冲,使用字节可以处于"未读取"状态。

换言之,可以添加byte到流里面,然后读取它。

PushbackInputStream允许程序在读取时往流里添加数据。

下次从这个流中读取数据,这些未被读取的数据将被读取。


默认情况下,这个流的buffer只有1字节长。

你可以通过构造方法来修改它.

public PushbackInputStream(InputStream in)
public PushbackInputStream(InputStream in, int size)

Unread data 将被放入栈中。

也就是如果你添加0,1,2 最终读出来会是2,1,0

样例代码如下:

PushbackInputStream in = new PushbackInputStream(System.in, 5);
in.unread(0);
in.unread(1);
in.unread(2);
System.out.println(in.read( ));
System.out.println(in.read( ));
System.out.println(in.read( ));

使用场景:

考虑Java语句 int count=7;. 编译器并不知道t是变量名的最后一个字母,直到读到等于号"="。

这时,可以unread =号

另一个是添加一些东西,如Unix和Mac的换行分割的问题。


你可能感兴趣的:(Java,JavaIO,JavaSE)