【问题标题】:Java InputStream's read(byte[]) methodJava InputStream 的 read(byte[]) 方法
【发布时间】:2013-03-16 19:08:48
【问题描述】:

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

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

【问题讨论】:

    标签: java io


    【解决方案1】:

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

    从输入流中读取一些字节并将它们存储到 缓冲区数组 b.实际读取的字节数返回为 一个整数。此方法阻塞,直到输入数据可用,结束 检测到文件,或者抛出异常。

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

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

    【讨论】:

    • 谢谢。你们是绝对正确的。感谢您花时间回答我的问题。
    • @jonericwennerstrom 不客气。请记得accept对您帮助最大的答案。
    【解决方案2】:

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

    没有。这就是为什么documentation 会说“实际读取的字节数”和“尝试读取至少一个字节”的原因。

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

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

    【讨论】:

    • 或者,如果您不想依赖第三方库,您可以将 InputStream 包装在 DataInputStream 中并使用 DataInputStream.readFully(byte[]) 方法。
    • 非常感谢您的回答。只需 4-5 行代码即可将调用置于循环中,而不是引入第 3 方依赖项。
    猜你喜欢
    • 1970-01-01
    • 2015-05-30
    • 1970-01-01
    • 1970-01-01
    • 2017-04-16
    • 1970-01-01
    • 2015-03-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多