9

在回答我对文件阅读问题的回答时,一位评论者表示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

4

6 回答 6

6

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

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

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

从此输入流中读取最多字节的数据到字节数组中。 b.length

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

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


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

于 2011-05-25T13:07:04.880 回答
6

什么可能导致读取方法无法检索整个文件内容?

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

现在我不知道是否有任何实现实际上是这样工作的,但关键是你不能依赖被填充的缓冲区,因为 API 合同不能保证它。

于 2011-05-25T13:18:06.853 回答
3

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

规范说该方法将返回 -1 指示流结束或将阻塞直到至少读取一个字节。的实现者InputStream可以在他们认为合适的情况下进行优化(例如,无论调用者选择的缓冲区大小如何,TCP 流可能会在数据包进入时立即返回数据)。AFileInputStream可能会用一个块的数据填充缓冲区。作为调用者,除了方法返回之前,您不知道-1,您需要继续阅读。

编辑

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

于 2011-05-25T13:04:24.433 回答
2

人们已经谈论在 a 上读取FileInputStream假设没有填充缓冲区。事实上,在某些情况下这是一个现实:

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

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

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

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

于 2011-05-25T13:44:23.373 回答
1

不保证填充缓冲区。

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

于 2011-05-25T13:06:20.920 回答
0

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

于 2011-05-26T00:01:00.153 回答