Java INPUTSTREAM如何實(shí)現(xiàn)重復(fù)使用
引語:
之前做項(xiàng)目的時(shí)候遇到一個(gè)問題,就是從網(wǎng)絡(luò)中讀取的圖片要上傳到oss,而且要對圖片進(jìn)行裁剪和壓縮,其中上傳和裁剪都要使用到圖片的inputStream,
又因?yàn)閕nputstream不能重復(fù)讀,導(dǎo)致裁剪是成功的,而上傳是失敗的.我們今天就提供兩種方法來解決,inputStream不能重復(fù)讀的問題.
問題分析:
inputStream的內(nèi)部有個(gè)pos指針,當(dāng)讀取的時(shí)候指針會(huì)不斷的移動(dòng),當(dāng)移動(dòng)到末尾的時(shí)候,就無法再次讀取了.
我們寫個(gè)簡單的例子來看下:
String text = "測試inputStream內(nèi)容";
InputStream inputStream = new ByteArrayInputStream(text.getBytes());
byte[] readArray = new byte[inputStream.available()];
int readCount1 = inputStream.read(readArray);
System.out.println("讀取了" + readCount1 + "個(gè)字節(jié)");byte[] readArray2 = new byte[inputStream.available()];
int readCount2 = inputStream.read(readArray2);
System.out.println("讀取了" + readCount2 + "個(gè)字節(jié)");
/**
* 執(zhí)行結(jié)果是
* 讀取了23個(gè)字節(jié)
* 讀取了-1個(gè)字節(jié)
*/
從執(zhí)行結(jié)果可以看出確實(shí)inputstream的設(shè)計(jì)是只能讀取一次.
注意: 這里稍微提一下inputStream.available()這個(gè)方法,本地的文件可以直接知道文件的大小,但是如果是網(wǎng)絡(luò)中的數(shù)據(jù),這個(gè)方法最好不要用,因?yàn)閭鬏數(shù)臅r(shí)候不是連續(xù)的,數(shù)據(jù)的大小會(huì)讀取不準(zhǔn)
問題解決:
那么我們實(shí)際項(xiàng)目中應(yīng)該怎么解決呢?總不能就真的只使用一次inputSteam吧.我們來看解決方法:
方法一:
使用ByteArrayOutputStream來緩存字節(jié),然后每次讀取從緩存的ByteArrayOutputStream中拿取.
很自然的想到把inputStream的緩存起來(當(dāng)然不一定說是要放在ByteArrayOutputStream,其他的方式也可以,都是緩存起來的思路,實(shí)現(xiàn)方式有很多種,這種比較方便)
String text = "測試inputStream內(nèi)容";
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 + "個(gè)字節(jié)");
System.out.println("讀取了" + readCount2 + "個(gè)字節(jié)");
/**
* 執(zhí)行結(jié)果是
* 讀取了23個(gè)字節(jié)
* 讀取了23個(gè)字節(jié)
*
這里是先將inputStream的數(shù)據(jù)讀取到output中,然后要反復(fù)使用inputStream中的內(nèi)容的時(shí)候,我們將output中的數(shù)據(jù)取出(很神奇的設(shè)定,output可以反復(fù)取,input只能讀一次)
方法二:
其實(shí)inputStream中有操作指針的方法,mark和reset,聽名字就知道是標(biāo)記和重置.在使用inputSteam前我們標(biāo)記下inputStream指針的位置,讀取完之后,重置,然后就可以反復(fù)使用了.我們看代碼:
String text = "測試inputStream內(nèi)容";
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 + "個(gè)字節(jié)");
System.out.println("讀取了" + readCount2 + "個(gè)字節(jié)");
總結(jié):
1.inputStream只能讀取一次,也就是說只能調(diào)用read()或者其他的帶參數(shù)的read()方法一次,在下次調(diào)用讀取出來是-1,做項(xiàng)目的時(shí)候不要忘記這一點(diǎn)了,可能會(huì)導(dǎo)致有些坑出現(xiàn);
2.可以使用緩存或者mark/reset方法來重復(fù)使用inputStream,這里要注意的是如果inputStream如果內(nèi)容很多,緩存不是一個(gè)好辦法,因?yàn)樵谑褂猛曛皶?huì)占用大量的內(nèi)存(我遇到過這樣的,上傳很多圖片然后還有緩存,導(dǎo)致內(nèi)存不夠就一直fullGC,然后cpu先爆了);
3.還有一個(gè)小點(diǎn)就是別忘了關(guān)閉使用完的inputStream/outputSteam.
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
SpringBoot @value注解動(dòng)態(tài)刷新問題小結(jié)
@Value注解 所對應(yīng)的數(shù)據(jù)源來自項(xiàng)目的 Environment 中,我們可以將數(shù)據(jù)庫或其他文件中的數(shù)據(jù),加載到項(xiàng)目的 Environment 中,然后 @Value注解 就可以動(dòng)態(tài)獲取到配置信息了,這篇文章主要介紹了SpringBoot @value注解動(dòng)態(tài)刷新,需要的朋友可以參考下2023-09-09
Java使用CountDownLatch實(shí)現(xiàn)統(tǒng)計(jì)任務(wù)耗時(shí)
這篇文章主要為大家詳細(xì)介紹了Java如何使用CountDownLatch實(shí)現(xiàn)統(tǒng)計(jì)任務(wù)耗時(shí)的功能,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解一下2023-06-06
詳解如何將springboot項(xiàng)目導(dǎo)出成war包
這篇文章主要介紹了詳解如何將springboot項(xiàng)目導(dǎo)出成war包,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-10-10
Java commons-httpclient如果實(shí)現(xiàn)get及post請求
這篇文章主要介紹了Java commons-httpclient如果實(shí)現(xiàn)get及post請求,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-09-09
Java中LambdaQueryWrapper的常用方法詳解
這篇文章主要給大家介紹了關(guān)于Java中LambdaQueryWrapper常用方法的相關(guān)資料,lambdaquerywrapper是一個(gè)Java庫,用于構(gòu)建類型安全的Lambda表達(dá)式查詢,需要的朋友可以參考下2023-11-11
Java實(shí)現(xiàn)短信驗(yàn)證碼的示例代碼
本文主要介紹了Java實(shí)現(xiàn)短信驗(yàn)證碼的示例代碼,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-03-03
Java?數(shù)據(jù)結(jié)構(gòu)與算法系列精講之貪心算法
我們可能在好多地方都會(huì)聽到貪心算法這一概念,并且它的算法思想也比較簡單就是說算法只保證局部最優(yōu),進(jìn)而達(dá)到全局最優(yōu)。但我們實(shí)際編程的過程中用的并不是很多,究其原因可能是貪心算法使用的條件比較苛刻,所要解決的問題必須滿足貪心選擇性質(zhì)2022-02-02

