Java:从InputStream读取并不总是读取相同数量的数据

无论好坏,我一直在使用以下代码,没有任何问题:

ZipFile aZipFile = new ZipFile(fileName); InputStream zipInput = aZipFile.getInputStream(name); int theSize = zipInput.available(); byte[] content = new byte[theSize]; zipInput.read(content, 0, theSize); 

我已经使用它(这个获取可用大小并直接读取到字节缓冲区的逻辑)来处理File I / O而没有任何问题,我也将它与zip文件一起使用。

但最近我进入了一个zipInput.read(content, 0, theSize); 实际上比theSize可用的读取少3个字节。

并且因为代码不在循环中来检查zipInput.read(content, 0, theSize);返回的长度zipInput.read(content, 0, theSize); 我读取了丢失3个最后一个字节的文件
后来程序无法正常运行(文件是二进制文件)。

奇怪的是,不同的较大尺寸的zip文件,例如1075字节(在我的情况下,有问题的zip条目是867字节)代码工作正常!

我知道代码的逻辑可能不是“最好的”,但为什么我现在突然遇到这个问题?

如果我立即使用更大的zip条目运行该程序怎么办?

任何意见都非常欢迎

谢谢

InputStream read API文档:

尝试读取len个字节,但可以读取较小的数字。

……并且:

返回:读入缓冲区的总字节数,如果由于已到达流末尾而没有更多数据,则返回-1。

换句话说,除非read方法返回-1,否则仍有更多数据可供读取,但您无法保证read完全读取指定的字节数。 指定的字节数是描述其将读取的最大数据量的上限

使用available()并不能保证它计算到end of stream总可用字节数。
请参阅Java InputStreamavailable()方法 。 它说

返回可以从此输入流中读取(或跳过)的字节数的估计值,而不会被下一次调用此输入流的方法阻塞。 下一次调用可能是同一个线程或另一个线程。 单个读取或跳过这么多字节不会阻塞,但可以读取或跳过更少的字节。

请注意,虽然InputStream某些实现将返回流中的总字节数,但许多实现不会。 使用此方法的返回值来分配用于保存此流中所有数据的缓冲区绝对不正确。

您的问题的示例解决方案可以如下:

 ZipFile aZipFile = new ZipFile(fileName); InputStream zipInput = aZipFile.getInputStream( caImport ); int available = zipInput.available(); byte[] contentBytes = new byte[ available ]; while ( available != 0 ) { zipInput.read( contentBytes ); // here, do what ever you want available = dis.available(); } // while available ... 

这适用于所有大小的输入文件。

这样做的最好方法应该是风箱:

 public static byte[] readZipFileToByteArray(ZipFile zipFile, ZipEntry entry) throws IOException { InputStream in = null; try { in = zipFile.getInputStream(entry); return IOUtils.toByteArray(in); } finally { IOUtils.closeQuietly(in); } } 

其中IOUtils.toByteArray(in)方法保持读取直到EOF,然后返回字节数组。