輸入流的複用在實際的開發中是很常見的場景。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();
將流轉化成爲數據流類
這一種方案就是將流中的數據所有讀取到一個字節數組中。在不一樣的數據接收者之間這些數據的傳遞是經過字節數組完成的。
將 字節流轉化成字節數組 可使用咱們 ByteArrayInputStream
,ByteArrayOutputStream
。這樣的話,咱們傳遞的是數據,而再也不是原始的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性能。