1

我想使用“BufferedReader”读取实时日志文件,并将新添加的内容打印到控制台:

File logfile = new File("logFile.txt");
BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(logfile)));
while(true) {
    String line = reader.readLine();
    System.out.println(line);
    Thread.sleep(1000L);
}

它会打印新添加的行,有时会打印null(意味着没有新行附加到日志中)。

我的问题是是否reader.readLine()会在某些情况下被阻止?在我的测试中,它不会阻塞,但我不确定它是否总是如此。

4

3 回答 3

3

我的问题是是否reader.readLine()会在某些情况下被阻止?

如果您正在读取的文件是本地文件系统中的常规文件,则它不太可能阻塞相当长的时间。事实上,只有在必须等待从磁盘读取数据时才可能完全阻塞。块时间可能在 10 毫秒的数量级。

如果该文件是远程安装的文件系统,那么您可能会遇到明显的延迟。事实上,在某些情况下,延迟可能会无限期地延长;例如,在远程服务器重新启动后使用远程 NFS 挂载(取决于挂载选项...)。

如果文件是某种类型的“特殊文件”(例如磁带驱动器),那么也可能会出现明显的延迟。(套接字和管道流也会阻塞,尽管这与您的示例代码无关。)


在正常情况下,很难在测试用例中导致读取可靠地阻塞。


您似乎正在尝试实现一个类或方法,该类或方法不断读取写入日志文件末尾的行。有现有的课程可以做到这一点;例如 Apache 公共Tailer类。我建议您重用Tailer或类似的东西,而不是重新发明轮子。

于 2013-11-11T08:56:23.727 回答
1

是的,它会阻塞,但不会在相当长的时间间隔内阻塞,除非说您正在从网络驱动器读取并且网络发生了奇怪的事情。具有动态生产者的管道是另一个示例。

在我的测试中,它不会阻塞

它不会在 EOF 处阻塞,这可能是您真正想知道的。怎么可能?

将打印 null (意味着没有新行附加到日志)

这意味着您已尝试阅读过去的 EOF。

读取自己的日志文件的系统对我来说很糟糕。如果您需要系统与自身通信,请实现它。

于 2013-11-11T08:46:50.583 回答
1

由于您正在从阻塞中读取FileInputStream,因此在操作系统从永久存储中读取数据时,执行将在短时间内阻塞。即使文件存储在本地磁盘上,也必须旋转磁盘并且必须将读取头移动到正确的位置,这需要时间,因为两者都是物理对象,在此期间您的程序除了等待什么也不做.

readLine方法null在到达文件末尾时返回。发生这种情况时,您要做的是等待文件更新,然后尝试阅读更多内容:

while(true) {
    String line = reader.readLine();
    if (line == null) {
        Thread.sleep(1000L);
        continue;
    }
    System.out.println(line);
}

实际上这也不是完美的,因为如果日志文件的最后一行不完整,则readLine返回它,并且当外部进程写入该行的其余部分时,您将通过单独调用readLine. 净效果:输出中可能会拆分某些行。

于 2013-11-11T08:55:04.553 回答