Java InputStream的read(byte )方法

首先是一些背景。 它不需要回答实际的问题,但也许它有助于把事情放在眼里。

我在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)? 也就是说,我是否假设读取(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 } 

您的结论是合理的,请查看InputStream.read(byte[])的文档:

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

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

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

因此我的问题是:通常,我是否可以假设InputStream的read(byte [])方法将被阻塞,直到读取了整个字节数(或达到EOF)?

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

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

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