怎麼重複使用inputStream?

https://segmentfault.com/a/1190000019624770java

引語:

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

問題分析:

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只能讀一次)spa

方法二
其實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.指針

相關文章
相關標籤/搜索