解決InputStream.available()獲取流大小問題
InputStream.available()獲取流大小問題
近日在學(xué)習(xí)IOUtils時(shí),模擬從網(wǎng)絡(luò)上讀取數(shù)據(jù)存放到本地磁盤,想使用InputStream.available()查看流的大小,結(jié)果發(fā)現(xiàn)得到的大小跟實(shí)際生成文件的大小不一致。
上代碼:
InputStream in = new URL("http://www.apache.org").openStream(); ? System.out.println(in.available());? FileOutputStream out = new FileOutputStream("F://1.html"); ? //這里返回的i可以認(rèn)為是流的大小 int i = IOUtils.copy(in, out);? System.out.println(i); ? IOUtils.closeQuietly(out);? IOUtils.closeQuietly(in);?
輸出結(jié)果:
10660
60787
很顯然,按照我們之前的理解,這兩個(gè)輸出得到的數(shù)據(jù)應(yīng)該是一樣的。后一個(gè)輸出的文件大小是沒有問題的,寫入到硬盤上就是那么多字節(jié)。那么前一個(gè)輸出的問題到底在哪呢?
通過查看api,發(fā)現(xiàn)了些端倪。該方法的描述是這樣的:返回可以不受阻塞地從此文件輸入流中讀取的字節(jié)數(shù)
如上,由于是從網(wǎng)絡(luò)中獲取數(shù)據(jù),由于存在著網(wǎng)絡(luò)延遲等因素,所以也就不難理解 兩次輸出不一致了。
當(dāng)然,如果是讀取本地文件的話,這個(gè)方法返回的數(shù)據(jù)大小一般是真實(shí)的。因此,如何使用以及要不要用這個(gè)方法,得根據(jù)具體的場(chǎng)景
若想獲取網(wǎng)絡(luò)中流的總大小,可以借助URLConnection方法
URLConnection openConnection = new URL("http://www.apache.org").openConnection();? System.out.println(openConnection.getContentLength());
InputStream.available()使用大坑
問題場(chǎng)景
文件下載功能,需要對(duì)原來的文件進(jìn)行讀取再輸出到文件或?yàn)g覽器中,會(huì)常用到InputStream.available()方法。
經(jīng)歷過一次系統(tǒng)功能變更升級(jí),需要將文件先下載到本地再響應(yīng)出去,發(fā)現(xiàn)下載的文件不全
百思不得其解,搜索好久資料,查找得知,以備忘記
這個(gè)方法可以在讀寫操作前先得知數(shù)據(jù)流里有多少個(gè)字節(jié)可以讀取。
- 需要注意的是,如果這個(gè)方法用在從本地文件讀取數(shù)據(jù)時(shí),一般不會(huì)遇到問題,
- 但如果是用于網(wǎng)絡(luò)操作,就經(jīng)常會(huì)遇到一些麻煩。比如,Socket通訊時(shí),
- 對(duì)方明明發(fā)來了1000個(gè)字節(jié),但是自己的程序調(diào)用available()方法卻只得到900,
- 或者100,甚至是0,感覺有點(diǎn)莫名其妙,怎么也找不到原因。
- 其實(shí),這是因?yàn)榫W(wǎng)絡(luò)通訊往往是間斷性的,一串字節(jié)往往分幾批進(jìn)行發(fā)送。
- 本地程序調(diào)用available()方法有時(shí)得到0,這可能是對(duì)方還沒有響應(yīng),也可能是對(duì)方已經(jīng)響應(yīng)了,
- 但是數(shù)據(jù)還沒有送達(dá)本地。對(duì)方發(fā)送了1000個(gè)字節(jié)給你,也許分成3批到達(dá),
- 這你就要調(diào)用3次available()方法才能將數(shù)據(jù)總數(shù)全部得到。
所以在進(jìn)行網(wǎng)絡(luò)數(shù)據(jù)傳輸時(shí)候,不能使用InputStream.available(),這個(gè)方法導(dǎo)致系統(tǒng)出現(xiàn)長(zhǎng)時(shí)間暫停狀態(tài)
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
SpringBoot整合阿里云OSS對(duì)象存儲(chǔ)服務(wù)實(shí)現(xiàn)文件上傳
這篇文章主要介紹了SpringBoot整合阿里云OSS對(duì)象存儲(chǔ)實(shí)現(xiàn)文件上傳,幫助大家更好的理解和學(xué)習(xí)使用SpringBoot,感興趣的朋友可以了解下2021-04-04SpringBoot2.4.2下使用Redis配置Lettuce的示例
這篇文章主要介紹了SpringBoot2.4.2下使用Redis配置Lettuce,Springboot2.4.2下默認(rèn)使用的就是Lettuce而不是Jedis因此無需在依賴進(jìn)行排除Jedis,本文給大家介紹的非常詳細(xì),感興趣的朋友跟隨小編一起看看吧2022-01-01Java計(jì)算兩個(gè)程序運(yùn)行時(shí)間的實(shí)例
下面小編就為大家?guī)硪黄狫ava計(jì)算兩個(gè)程序運(yùn)行時(shí)間的實(shí)例。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-04-04Idea安裝及涉及springboot詳細(xì)配置的圖文教程
這篇文章主要介紹了Idea安裝及涉及springboot詳細(xì)配置,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-10-10Java中的CAS鎖機(jī)制(無鎖、自旋鎖、樂觀鎖、輕量級(jí)鎖)詳解
這篇文章主要介紹了Java中的CAS鎖機(jī)制(無鎖、自旋鎖、樂觀鎖、輕量級(jí)鎖)詳解,CAS算法的作用是解決多線程條件下使用鎖造成性能損耗問題的算法,保證了原子性,這個(gè)原子操作是由CPU來完成的,需要的朋友可以參考下2024-01-01