FileInputStream.read(byte [])有什么问题?

时间:2011-05-25 13:01:45

标签: java java-io fileinputstream

在回复my answer to a file-reading question时,一位意见提供者表示FileInputStream.read(byte[])“无法保证填补缓冲区。”

File file = /* ... */  
long len = file.length();
byte[] buffer = new byte[(int)len];
FileInputStream in = new FileInputStream(file);
in.read(buffer);

(代码假定文件长度不超过2GB)

除了IOException之外,是什么原因导致read方法无法检索整个文件内容?

修改

代码的概念(以及我回答的问题的OP的目标)是一举将整个文件读入一块内存,这就是为什么 buffer_size = FILE_SIZE

6 个答案:

答案 0 :(得分:6)

  

什么可能导致read方法   不检索整个文件内容?

例如,如果文件在文件系统上被分段,并且低级实现知道它必须等待HD寻找下一个片段(这相对于CPU需要很多时间)操作),read()调用返回时返回部分缓冲区未填充,以便应用程序有机会对已收到的数据执行某些操作。

现在我不知道任何实现是否实际上都是这样的,但关键是你必须依赖于填充的缓冲区,因为API协议无法保证。

答案 1 :(得分:5)

  

除了IOException之外,什么可能导致read方法无法检索整个文件内容?

在我自己的API实现中,在我的家庭滚动文件系统中,我只是选择填充缓冲区的一半......开个玩笑。

我的观点是,即使我不是在开玩笑,从技术上讲,这不会是一个错误。这是方法契约的问题。这是这种情况下的合同(文件):

  

将此输入流中最多 b.length个字节的数据读入一个字节数组。

即,它不能保证填充缓冲区。

根据API实现,可能在文件系统上,read方法可能选择不填充缓冲区。这基本上是该方法的合同所说的问题。


底线: 可能有效,但保证不起作用。

答案 2 :(得分:3)

嗯,首先,你已经让自己成为一个错误的二分法。一个完全正常的情况是缓冲区不会被填充,因为文件中没有剩余的字节。这不是IOException,但并不意味着整个文件的内容都没有被读取。

规范说该方法将返回-1表示流结束或将阻塞直到至少读取一个字节。 InputStream的实现者可以根据需要进行优化(例如,无论调用者选择缓冲区大小,TCP流都可以在数据包进入后立即返回数据)。 FileInputStream可能会在缓冲区中填充一个块的数据。作为调用者,你不知道,除非在方法返回-1之前,你需要继续阅读。

修改

实际上,在您的示例中,我将看到缓冲区未填充的唯一情况(使用标准实现)是在分配缓冲区之后但在开始读取之前文件更改了大小。由于您没有锁定文件,这是可能的。

答案 3 :(得分:2)

人们已经谈到在FileInputStream上读取假设没有填充缓冲区。实际上在某些情况下它是现实

  • 如果在“/ dev / tty”或命名管道上打开FileInputStream,则read只会返回当前可用的数据。其他设备文件可能的行为方式相同。 (这些文件可能会返回0L作为文件大小。)

  • 如果文件系统已使用direct_io选项挂载,或者使用相应的标志打开文件,则可以实现FUSE文件系统不会完全填充读取缓冲区。

以上内容适用于Linux,但其他操作系统和/或Java实现可能存在类似情况。底线是javadocs 允许这种行为,如果您的应用程序假定它不会发生,您可能会遇到麻烦。

有第三方库实现“完全读取”行为;例如Apache commons提供FileUtils.readFileToByteArrayIOUtils.toByteArray以及类似的方法。如果您想要/需要这种行为,您应该使用其中一个库,或者自己实现它。

答案 4 :(得分:1)

无法保证填充缓冲区。

文件大小可能小于缓冲区,或者文件的其余部分可能小于缓冲区。

答案 5 :(得分:0)

你的问题是自相矛盾的。无法保证它将读取整个缓冲区,即使没有可以想象的情况也不会。没有保证,所以你不能假设它。