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/15453472/

相关文章:

java - LocalDateTime 设置以秒为单位计算重叠

java - onActivityResult 无法正常工作

java - 循环单链表

android - 如何在Android/iOS上通过不同的线程同时读写一个文件?

C++ - 使用 io 重定向输入和输出多个整数

java - 如何等待文件创建

java - 如何使用 InputStream 加载 UTF-8 文本文件

java - Type=带有特殊字符的文本模式问题

java - 可以通过更改系统日期来绕过检查到期日期

c - 当我只需要一个输入时,为什么 getchar() 需要两个输入?