怎麼重複使用inputStream?

引語:

    以前作項目的時候遇到一個問題,就是從網絡中讀取的圖片要上傳到oss,並且要對圖片進行裁剪和壓縮,其中上傳和裁剪都要使用到圖片的inputStream,
又由於inputstream不能重複讀,致使裁剪是成功的,而上傳是失敗的.咱們今天就提供兩種方法來解決,inputStream不能重複讀的問題.java

問題分析:

inputStream的內部有個pos指針,當讀取的時候指針會不斷的移動,當移動到末尾的時候,就沒法再次讀取了.
咱們寫個簡單的例子來看下:緩存

String text = "測試inputStream內容";
    InputStream inputStream = new ByteArrayInputStream(text.getBytes());
    byte[] readArray = new byte[inputStream.available()];
    int readCount1 = inputStream.read(readArray);
    System.out.println("讀取了" + readCount1 + "個字節");

    byte[] readArray2 = new byte[inputStream.available()];
    int readCount2 = inputStream.read(readArray2);
    System.out.println("讀取了" + readCount2 + "個字節");
    /**
    *  執行結果是
    *  讀取了23個字節
    *  讀取了-1個字節
    */

從執行結果能夠看出確實inputstream的設計是隻能讀取一次.
注意: 這裏稍微提一下inputStream.available()這個方法,本地的文件能夠直接知道文件的大小,可是若是是網絡中的數據,這個方法最好不要用,由於傳輸的時候不是連續的,數據的大小會讀取不許網絡

問題解決:

那麼咱們實際項目中應該怎麼解決呢?總不能就真的只使用一次inputSteam吧.咱們來看解決方法:
方法一:
使用ByteArrayOutputStream來緩存字節,而後每次讀取從緩存的ByteArrayOutputStream中拿取.
很天然的想到把inputStream的緩存起來(固然不必定說是要放在ByteArrayOutputStream,其餘的方式也能夠,都是緩存起來的思路,實現方式有不少種,這種比較方便)測試

String text = "測試inputStream內容";
       InputStream rawInputStream = new ByteArrayInputStream(text.getBytes());
       ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
       byte[] buffer = new byte[1024];
       int len;
       while ((len = rawInputStream.read(buffer)) > -1) {
           outputStream.write(buffer, 0, len);
       }
       outputStream.flush();
       InputStream in1 = new ByteArrayInputStream(outputStream.toByteArray());
       InputStream in2 = new ByteArrayInputStream(outputStream.toByteArray());
       int readCount1 = in1.read(buffer);
       int readCount2 = in2.read(buffer);
       System.out.println("讀取了" + readCount1 + "個字節");
       System.out.println("讀取了" + readCount2 + "個字節");
       /**
       *  執行結果是
       *  讀取了23個字節
       *  讀取了23個字節
       *

這裏是先將inputStream的數據讀取到output中,而後要反覆使用inputStream中的內容的時候,咱們將output中的數據取出(很神奇的設定,output能夠反覆取,input只能讀一次)設計

方法二:
其實inputStream中有操做指針的方法,mark和reset,聽名字就知道是標記和重置.在使用inputSteam前咱們標記下inputStream指針的位置,讀取完以後,重置,而後就能夠反覆使用了.咱們看代碼:指針

String text = "測試inputStream內容";
      InputStream rawInputStream = new ByteArrayInputStream(text.getBytes());
      byte[] readArray = new byte[1024];
      rawInputStream.mark(0);
      int readCount1 = rawInputStream.read(readArray);
      rawInputStream.reset();
      int readCount2 = rawInputStream.read(readArray);
      System.out.println("讀取了" + readCount1 + "個字節");
      System.out.println("讀取了" + readCount2 + "個字節");

總結:

1.inputStream只能讀取一次,也就是說只能調用read()或者其餘的帶參數的read()方法一次,在下次調用讀取出來是-1,作項目的時候不要忘記這一點了,可能會致使有些坑出現;
2.可使用緩存或者mark/reset方法來重複使用inputStream,這裏要注意的是若是inputStream若是內容不少,緩存不是一個好辦法,由於在使用完以前會佔用大量的內存(我遇到過這樣的,上傳不少圖片而後還有緩存,致使內存不夠就一直fullGC,而後cpu先爆了);
3.還有一個小點就是別忘了關閉使用完的inputStream/outputSteam.code

相關文章
相關標籤/搜索