【问题标题】:Reading new data from a constantly updating file in Java从 Java 中不断更新的文件中读取新数据
【发布时间】:2018-12-27 18:46:52
【问题描述】:

我有一个不断更新新数据行的日志文件。我需要在写入后立即在 java 中获取新添加的数据。目前我的解决方案是:

public static void readNonStop(String filename, boolean goToEnd, FileReadCallback readCallback) {
    if(readCallback == null) {
        return;
    }
    try {
        BufferedReader br = new BufferedReader(new FileReader(filename));
        try {
            String line = br.readLine();
            int lineNumber = 0;

            if(goToEnd) {
                while(br.readLine() != null) {}
            }

            while (true) {
                if(line != null) {
                    readCallback.onRead(lineNumber++, line);
                } else {
                    Thread.sleep(1);
                }
                line = br.readLine();
            }
        } finally {
            br.close();
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
}

但我有一种感觉,应该有更好的方法。我不喜欢内部有“睡眠”的持续运行循环的想法,我更喜欢某种事件驱动的方法。

如果我在每次修改文件时都依赖 FileSystem 事件重新打开文件,则会产生延迟。

对于这种情况,正确的做法是什么?

提前致谢!

【问题讨论】:

标签: java io file-read


【解决方案1】:

文件并非旨在作为消息传递解决方案。即使使用 TCP over loopback 也会有 10 - 30 微秒的延迟。在不更改文件格式的情况下,您的解决方案可能是最快的。

注意:您不必睡一整毫秒。您可以使用 Thread.yield()LockSupport.parkNanos(100_000); 对于更复杂的策略,您可以使用像 LongPauser 这样的类,它以可配置的方式回退。

顺便说一句,我实现了一种以低延迟方式写入/读取文件的解决方案,称为 Chronicle Queue。这具有亚微秒级的延迟,使用二进制格式来提高速度。

注意:当您将文件作为 FileInputStream 打开时,您可以跳过所有字节 available() 直到最后。这可能会导致行不完整,具体取决于您的缓冲工作方式。

【讨论】:

  • 感谢您的回答。目前我唯一不喜欢这个解决方案的是如果没有“Thread.sleep”,CPU 就会受到压力。睡眠时间至少为 1 毫秒,CPU 使用率会从 40% 下降到 0-1%。在某些情况下,使用 WatchService 会导致最多 5-6 秒的延迟,这是不可接受的。问题是,这是获取所需信息的唯一方法,所以我无法切换通信方式。我应该改用 FileInputStream。
  • 您可能会发现睡眠时间超过 10 毫秒是可以的。 LongPauser 所做的就是休眠越来越长的时间,直到您调用 reset()。这最大限度地减少了事情繁忙的延迟。
  • 在代码审查中,我收到了使用 Apache commons 中的 Tailer 类的建议。看看它的代码,看起来我的想法是正确的。 Tailer 虽然更健壮一点,但使用与我的代码相同的逻辑,但它在循环中读取,并有 Thread.sleep 延迟。
  • 文件并非旨在成为消息传递解决方案。确实如此。这是一个非常糟糕的设计——尤其是在使用 Java 的情况下。使用低级 C 代码读取不断变化/增长的文件非常困难,以使其可靠。对于 Java,这事实上是不可能的,因为例如,您无法控制 JVM 是否缓存文件大小。
  • @AndrewHenle,我正在为游戏编写一个 RGB 键盘集成,从中获取信息的唯一方法(没有明显侵入内存)是读取它的日志文件,这些文件会立即更新为游戏中一旦发生事件。
猜你喜欢
  • 2013-05-19
  • 2021-02-14
  • 2014-09-30
  • 1970-01-01
  • 2010-10-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多