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性能。
相關文章
相關標籤/搜索