2013-03-16 91 views
2

首先一些背景知識。 它不需要回答實際的問題,但也許它會幫助把事情放在角度。爪哇的InputStream的read(字節[])方法

我在java(h)中編寫了一個mp3庫,它讀取存儲在.mp3文件中ID3標記中的信息。關於喜歡的歌,光盤中的歌曲被釋放,軌道號等名稱的歌曲信息存儲在該ID3標籤就在.mp3文件的開頭。

我已經測試了位於我本地硬盤驅動器上的12,579個mp3文件的庫,它的工作原理完美無瑕。沒有一個IO錯誤。

當我在mp3服務器上執行相同的事情時,我得到一個IO錯誤。那麼,不是一個錯誤。實際上它是InputStream的read(byte [])方法的行爲差異。

下面的例子將說明當我試圖從mp3文件讀取圖像文件(.jpg,.gif,.png等)時發生的問題。

// read bytes from an .mp3 file on your local hard drive 
// reading from an input stream created this way works flawlessly 
InputStream  inputStream = new FileInputStream("song.mp3"); 

// read bytes from an .mp3 file given by a url 
// reading from an input stream created this way fails every time. 
URL    url   = "http://localhost/song.mp3"); 
HttpURLConnection httpConnection = (HttpURLConnection)url.openConnection(); 
httpConnection.connect(); 
InputStream  inputStream = url.openStream(); 


int size   = 25000;   // size of the image file 
byte[] buffer  = new byte[size]; 
int numBytesRead = inputStream.read(buffer); 

if (numBytesRead != buffer.length) 
    throw new IOException("Error reading the bytes into the buffer. Expected " + buffer.length + " bytes but got " + numBytesRead + " bytes"); 

所以,我的觀察是: 調用inputStream.read(緩衝);當輸入流是FileInputStream時,總是讀取整個字節數。但是,當我使用從http連接獲取的輸入流時,它只會讀取部分數量。

因此我的問題是: 一般來說,我可以不假設InputStream的read(byte [])方法會阻塞,直到整個字節數已被讀取(或達到EOF)? 也就是說,有我假設的行爲,是不是讀(字節[])方法的真實的,我剛剛得到了幸運的FileInputStream工作?

InputStream.read(byte [])是否需要將該調用放到一個循環中並保持讀取字節,直到讀取了所需的字節數或已達到EOF爲止,是否正確並且是普遍行爲?

int size  = 25000; 
byte[] buffer  = new byte[size]; 
int numBytesRead = 0; 
int totalBytesRead = 0; 

while (totalBytesRead != size && numBytesRead != -1) 
{ 
    numBytesRead = inputStream.read(buffer); 
    totalBytesRead += numBytesRead 
} 

回答

3

你的結論是合理的,看看該文檔InputStream.read(byte[]):如下面的代碼東西

讀取從輸入流的字節,並將它們存儲一些數到 在緩衝區數組灣實際讀取的字節數作爲整數返回爲 。此方法阻塞,直到輸入數據可用,檢測到文件末尾 或引發異常。

沒有保證read(byte[])將填補你所提供的陣列,只知道它要麼讀至少1個字節(前提是您的數組的長度> 0),否則它會返回-1信號的EOS 。這意味着如果您想正確讀取InputStream的字節,則必須使用循環。

您目前擁有的循環中有一個錯誤。在循環的第一次迭代中,你會讀到一個特定字節數到您的緩衝區,但在第二次迭代將覆蓋部分或全部,這些字節。看看InputStream.read(byte[], int, int)

+0

謝謝。你們是絕對正確的。感謝您花時間回答我的問題。 – 2013-03-17 15:03:51

+0

@jonericwennerstrom不客氣。請記住[接受](http://meta.stackexchange.com/a/5235/193053)對您最有幫助的答案。 – Jeffrey 2013-03-17 15:05:36

+0

@Downvoter我可以詢問爲什麼? – Jeffrey 2013-03-17 22:07:45

3

因此,我的問題是:一般來說,我可以不假設InputStream的read(byte [])方法會阻塞,直到整個字節數已被讀取(或EOF已達到)?

不。這就是爲什麼documentation表示「實際讀取的字節數」和「試圖讀取至少一個字節」。

我需要把在一個循環中調用,並保持讀取字節,直到所需的字節數已經閱讀

而不是推倒重來,就可以得到在Jakarta Commons IO已經測試輪。

+0

或者,如果您不想依賴第三方庫,則可以將InputStream包裝在DataInputStream中並使用DataInputStream.readFully(byte [])方法。 – VGR 2013-03-17 13:44:17

+0

非常感謝您的回答。這隻需要4-5行代碼將呼叫置於循環中,而不是引入第三方依賴關係。 – 2013-03-17 15:02:53