InputStream重用

網上所找到的大多是利用 ByteArrayOutputStreamByteArrayInputStream 之前的相互轉換來實現的。
具體看下列代碼

InputStream input =  httpconn.getInputStream();
	            
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len;
while ((len = input.read(buffer)) > -1 ) {
	baos.write(buffer, 0, len);
}
baos.flush();	           
 
InputStream stream1 = new ByteArrayInputStream(baos.toByteArray());
 
//TODO:顯示到前臺
 
InputStream stream2 = new ByteArrayInputStream(baos.toByteArray());
 
//TODO:本地緩存

摘抄自這篇博客InputStream重用技巧(利用ByteArrayOutputStream)

秉着 “拿來思考主義” ,上述代碼存在着嚴重的浪費內存以及效率問題;每次複用,需要重新拷貝數組,即浪費了時間,又浪費了空間。顯然,這不會是處女座的程序員想要的。

不知道大家想到過這種用法嘛?mark 方法 和 reset 方法結合來實現重用(他們會共用一份存儲空間,如果你的沒有併發的問題,我覺得使用這個是沒問題的)。不過存在某些實現流不支持這兩種方法,像 FileInputStream 。不過還好包裝器模式的完美之處開始體現,功能性流 BufferedInputStream 可以彌補這個不足。附上代碼:

BufferedInputStream bufferedInputStream = new BufferedInputStream(file.getInputStream());
// 這裏爲什麼加一,是因爲我們需要重用整個流可讀取字節,如果不加1,會失敗掉,具體失敗原因可以查看異常拋出點
bufferedInputStream.mark(bufferedInputStream.available() + 1);

// 第一次使用 bufferedInputStream 直接使用即可

// 第二次使用 bufferedInputStream ,需要先 reset
bufferedInputStream.reset();

上面也提到,如果有併發的原因,也就是同一個 BufferedInputStream 實例化對象被多個線程使用,這樣就會存在問題了。原因也很好理解,BufferedInputStream 實例化對象中存在一些狀態,像 pos, markpos 等 ,多線程下修改這些狀態就會出現問題了。我給出的解決方案是使用 ThreadLocal ,或者使用文章開頭所提到的方法也行。


辦法多多,歡迎留言討論。另外,可能也存在未考慮到的其它情況,希望猿友們能留言給出疑問,也能給後續閱讀的博友們起到解讀的作用。

由於 available 方法,返回的並不是一個確切值,上述方法的可用性還是有待商酌啊,不過我目前是這樣使用的,並未出現問題。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章