首先是一些背景。 它不需要回答实际的问题,但也许它有助于把事情放在眼里。
我在java(h)中编写了一个mp3库,它读取存储在.mp3文件中的ID3标签中的信息。有关歌曲的信息,如歌曲的名称,发行歌曲的CD,曲目编号等,都存储在.3文件开头的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
}
答案 0 :(得分:3)
您的结论是合理的,请查看InputStream.read(byte[])
的文档:
从输入流中读取一些字节并将其存储到 缓冲阵列b。实际读取的字节数返回为 整数。此方法将阻塞,直到输入数据可用,结束 检测到文件,或抛出异常。
无法保证read(byte[])
将填充您提供的数组,只能读取至少1个字节(假设您的数组长度为> 0),或者它将返回-1以发出信号EOS。这意味着如果要正确读取InputStream
中的字节,则必须使用循环。
您目前拥有的循环中有一个错误。在循环的第一次迭代中,您将在缓冲区中读取一定数量的字节,但在第二次迭代中,您将覆盖这些字节中的一些或全部。看看InputStream.read(byte[], int, int)
。
答案 1 :(得分:3)
因此我的问题是:通常,我不能假设InputStream的read(byte [])方法将被阻塞,直到读取了整个字节数(或达到EOF)?
没有。这就是documentation说"实际读取的字节数"和"试图读取至少一个字节。"
我需要将调用置于循环中并继续读取字节,直到读取了所需的字节数
不是重新发明轮子,而是可以在Jakarta Commons IO获得已经过测试过的轮子。