java.io (2) 输入流的复用

输入流的复用在实际的开发中是很常见的场景。java

在实际应用中,不少须要提供输入数据的API都是用IputStream类做为其参数类型,好比XML文档的解析API就是一个典型的例子。同时不少数据的提供者容许使用者经过InputStream类的对象方式来读取数据。数组

图片描述

根据java对io的抽象(Stream),流的复用是矛盾的。按照流自己所表明的抽象含义,数据一旦流过去了,就没法被再次利用了。性能

对于现实应用中存在的对输入流的需求,基本上来讲的两种方式能够解决;第一种是利用输入流提供的标记和重置的控制能力,第二种则是把输入流转换成数据来使用。this

方法一, 缓冲流类标记与重置

好在java为咱们提供现成的解决方案。
BufferedInputStream, BufferedOutputStream
利用这两个类中提供的spa

public synchronized void mark(int readlimit) 读取位置标记,须要一个容许读取的字节数。
public synchronized void reset() throws IOException 将读取位置重置到标记位置。
public boolean markSupported() 检查当前流类是否支持标记功能code

这三个方法能有效地解决流复用的问题。对象

java// 假如咱们有三个方法,须要串行的使用咱们的 io 输入流。
   // public static void process1(InputStream in) throws IOException;
   // public static void process2(InputStream in) throws IOException;
   // public static void process3(InputStream in) throws IOException;

   if (!input.markSupported()) {
       this.input = new BufferedInputStream(input);
   }
   else
   {
       this.input = input;
   }

   // 为了可以复用整个流
   this.input.mark(Integer.MAX_VALUE); 

   process1(this.input);
   // 重置读取位置,以供下一个使用者使用,如下雷同
   this.input.reset();

   process2(this.input);
   this.input.reset();

   process3(this.input);
   this.input.reset();

方法二, 将流转化成为数据流类

这一种方案就是将流中的数据所有读取到一个字节数组中。在不一样的数据接收者之间这些数据的传递是经过字节数组完成的。
将 字节流转化成字节数组 可使用咱们 ByteArrayInputStreamByteArrayOutputStream。这样的话,咱们传递的是数据,而再也不是原始的io。图片

ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
   byte[] buffer = new byte[2048];
   for (int count=0; ( inputStream.read(buffer) ) != -1; ) {
        arrayOutputStream.write(buffer, 0, count);
   }

   ByteArrayInputStream byteArrayOutputStream = new ByteArrayInputStream(arrayOutputStream.toByteArray());

   // byteArrayOutputStream 对象就能够做为咱们须要复用的数据流,配合 `mark`和`reset` 功能提升io性能。
相关文章
相关标签/搜索