FileInputStream.read() 何时会阻塞?

5
这个问题类似于以下两个问题: 但我仍然不能完全理解它。
目前,我认为以下代码中的read()方法将由于空文件“test.txt”而被阻塞。
FileInputStream fis = new FileInputStream("c:/test.txt");
System.out.println(fis.read());
System.out.println("to the end");

事实上它会打印出-1,我想知道为什么。
Java文档中写到:“如果没有输入可用,此方法将被阻塞。”
“没有可用的输入”是什么意思?
谢谢。
4个回答

5
你的问题的答案可以在.read()的JavaDoc中找到:
该方法如果没有输入可用则会阻塞。
返回:下一个数据字节,如果到达文件结尾则为-1。
因此,空文件将立即获得-1(而不是read()阻塞),因为
  • 有输入可用,因为文件存在
  • ...但它是空的,所以立即EOF。
“...还没有可用的输入...”的情况可能发生在例如从命名管道而不是普通文件读取时,管道的另一侧尚未写入任何内容。
干杯,

当从管道而不是文件中读取时,除非另一方向管道写入数据,否则将无法获得任何内容 - 在这种情况下,.read() 将会阻塞。 - Anders R. Bystrup
请问您能否给我一个读取管道的示例?谢谢,因为我在FileInputStream的API中找不到相关函数。 - liam xu
1
如果您可以访问Linux系统,就像使用 mkfifo /tmp/mynamedpipe 那样简单,然后像处理常规文件一样打开 /tmp/mynamedpipe。使用 echo "whatever" > /tmp/mynamedpipe 可以通过管道传递数据。 - Anders R. Bystrup
不管文件是否为空,EOF(文件结束标志)都会在文件结尾处返回-1。所有的文件都有EOF。 - user207421
@EJP,我不否认这一点,但我认为OP的观点是为什么他得到了-1而不是read()在一个空文件上阻塞。我现在已经在答案中澄清了这一点。 - Anders R. Bystrup

3

FileInputStream可以用于读取除普通文件之外的其他内容。一个明显的例子是命名管道:如果在另一端未写入数据时尝试从管道中读取,读取操作将会阻塞。


如何从命名管道中读取数据?如何编写代码实现?我在 FileInputStream 的源代码中找不到相应的函数。 - liam xu
1
@liamxu:你可以像打开其他文件一样打开它。如果你想了解更多,我建议你查看我链接的维基百科页面。 - NPE

1
这可能是这样解释的:FileInputStream.read 调用原生方法,该原生方法执行 read system call 并阻塞等待操作系统将字节从文件读入缓冲区并在准备就绪时返回。也就是说,FileInputStream.read 使用同步 I/O 从文件中读取数据,而非非阻塞异步 I/O。

1
你不能把“没有可用的输入”解释为“您已定位到EOF,将不再有更多输入可用”。它们是不同的条件。后者返回-1。
通常情况下,从文件中进行的所有读取都会阻塞,直到数据可用。磁盘必须转到正确的位置,磁头必须搜索正确的轨道。您还需要考虑在共享驱动器上的文件或命名管道上的文件,这两种情况都涉及网络操作,也可能会阻塞。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接