2

最初にいくつかの背景。実際の質問に答える必要はありませんが、物事の見通しを立てるのに役立つかもしれません。

ID3タグに保存されている情報を.mp3ファイルで読み取るJava(h)でmp3ライブラリを作成しました。曲の名前、曲がリリースされたCD、トラック番号などの曲に関する情報は、.mp3ファイルの先頭にあるこのID3タグに保存されます。

ローカルハードドライブにある12,579mp3ファイルでライブラリをテストしましたが、問題なく動作します。単一のIOエラーではありません。

mp3ファイルがWebサーバー上にあるのと同じことを実行すると、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(buffer);を呼び出します。入力ストリームがFileInputStreamの場合、常にバイト数全体を読み取ります。ただし、http接続から取得した入力ストリームを使用している場合は、部分的な量しか読み取れません。

したがって、私の質問は次のとおりです。一般に、InputStreamのread(byte [])メソッドは、バイト数全体が読み取られる(またはEOFに達する)までブロックされると想定できませんか?つまり、read(byte [])メソッドには当てはまらない動作を想定していて、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
}
4

2 に答える 2

3

あなたの結論は正しいです、以下のドキュメントを見てくださいInputStream.read(byte[])

入力ストリームからいくつかのバイトを読み取り、それらをバッファ配列に格納します。実際に読み取られたバイト数は整数として返されます。このメソッドは、入力データが使用可能になるか、ファイルの終わりが検出されるか、例外がスローされるまでブロックします。

指定した配列がいっぱいになるという保証はありませんread(byte[])。少なくとも1バイトを読み取るか(配列の長さが0より大きい場合)、または-1を返してEOSに信号を送るだけです。InputStreamこれは、バイトを正しく読み取りたい場合は、ループを使用する必要があることを意味します。

現在のループには1つのバグがあります。ループの最初の反復では、特定のバイト数をバッファに読み込みますが、2回目の反復では、それらのバイトの一部またはすべてを上書きします。を見てくださいInputStream.read(byte[], int, int)

于 2013-03-16T19:23:38.437 に答える
3

したがって、私の質問は次のとおりです。一般に、InputStreamのread(byte [])メソッドは、バイト数全体が読み取られる(またはEOFに達する)までブロックされると想定できませんか?

いいえ。そのため、ドキュメントには「実際に読み取られたバイト数」と「少なくとも1バイトを読み取ろうとしている」と記載されています。

呼び出しをループに入れて、必要なバイト数が読み取られるまでバイトを読み取り続ける必要があります

ホイールを再発明するのではなく、 JakartaCommonsIOですでにテスト済みのホイールを入手できます。

于 2013-03-16T19:24:36.633 に答える