Java InputStream 的 read(byte[]) 方法

标签 java io

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

我在 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
}

最佳答案

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

Reads some number of bytes from the input stream and stores them into the buffer array b. The number of bytes actually read is returned as an integer. This method blocks until input data is available, end of file is detected, or an exception is thrown.



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

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

关于Java InputStream 的 read(byte[]) 方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36440992/

相关文章:

java - Spring - applicationContext.xml 中的路径

Java Swing : GUI is not updating some properties

java - 参数化类的原始使用

haskell - 如何在 Haskell 中组合句柄?

linux - blktrace只能跟踪一个特定的进程吗?

java - 通过互联网发送对象并调用它的方法

java - 如何使用正则表达式将字符串拆分为数组(通过不在括号内的逗号)?

haskell - 如何展平 IO [[String]]?

Perl:将 STDOUT 重定向到两个文件

java - 写入大量小文件