2

首先是一些背景。它不需要回答实际问题,但也许它会有助于正确看待事情。

我在 java (h) 中编写了一个 mp3 库,它读取存储在 .mp3 文件中 ID3 标记中的信息。有关歌曲的信息,如歌曲名称、歌曲发行的 CD、曲目编号等,都存储在 .mp3 文件开头的这个 ID3 标签中。

我已经在位于我本地硬盘上的 12,579 个 mp3 文件上测试了该库,并且它运行良好。没有一个 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[])

从输入流中读取一些字节并将它们存储到缓冲区数组 b. 实际读取的字节数以整数形式返回。在输入数据可用、检测到文件结尾或引发异常之前,此方法会一直阻塞。

不能保证read(byte[])会填充您提供的数组,只是它会读取至少 1 个字节(假设您的数组的长度 > 0),或者它将返回 -1 以指示 EOS。这意味着如果要InputStream正确读取字节,则必须使用循环。

您当前拥有的循环中有一个错误。在循环的第一次迭代中,您会将一定数量的字节读入缓冲区,但在第二次迭代中,您将覆盖部分或全部这些字节。看看InputStream.read(byte[], int, int)

于 2013-03-16T19:23:38.437 回答
3

因此我的问题是:一般来说,我不能假设 InputStream 的 read(byte[]) 方法会阻塞,直到读取了全部字节数(或达到 EOF)?

不,这就是为什么文档说“实际读取的字节数”和“尝试读取至少一个字节”的原因。

我需要将调用置于循环中并继续读取字节,直到读取所需的字节数

您可以在Jakarta Commons IO获得已经测试过的轮子,而不是重新发明轮子。

于 2013-03-16T19:24:36.633 回答