在回复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 的
答案 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.readFileToByteArray
或IOUtils.toByteArray
以及类似的方法。如果您想要/需要这种行为,您应该使用其中一个库,或者自己实现它。
答案 4 :(得分:1)
无法保证填充缓冲区。
文件大小可能小于缓冲区,或者文件的其余部分可能小于缓冲区。
答案 5 :(得分:0)
你的问题是自相矛盾的。无法保证它将读取整个缓冲区,即使没有可以想象的情况也不会。没有保证,所以你不能假设它。