如何在不打开文件的情况下跟踪像Java中的“Tail -f”那样的文件(防止重命名/删除)

2022-09-03 14:51:05

我想从Java应用程序中“Tail -f”很多日志文件。

我通过监视大小和上次更新,并在文件大小或上次更新时间发生变化时重复打开文件并读取最后几个字节来实现这一点 - 然后立即关闭它。

这似乎有问题,因为当记录器决定重命名文件时,我可能会将其打开,这将导致某种问题。

我还想检测一个“滚动”文件,其机制比注意到文件大小减小更确定...似乎容易出错,但不太可能。

由于我似乎无法访问文件描述符或其他低级文件实用程序,我可能无法重现尾部的行为 - 但是有什么技巧可以在不“锁定”文件以进行重命名/删除的情况下读取文件(Windows 7)

我猜另一种可能性是实际生成一个 tail -f 进程并读取进程输出,但这似乎有点沉重 - 我在这里扫描了 60 个日志文件,其中一些有很多输出(大多数将空闲)。


答案 1

Apache Commons有一个Tailer类,它会做你想要的吗?如果是这样,它具有滚动检测机制以及读取功能,因此您可以获得所需的一切。

如果这不能做到这一点,那可能是没有办法用纯java做到这一点。例如,您需要一些帮助,例如,使用带有SH_DENYNO参数的fopen,允许在窗口上共享打开。或者,只需通过执行系统命令来调用 tail 实现。

但是,由于打开日志文件的代码是导致锁定它的代码,因此即使这样也可能无济于事。在这种情况下,唯一真正的选择是更改日志记录的工作方式,因为这是锁定文件的罪魁祸首。Log4j可以使用SocketAppender等。


答案 2

使用 apache.commons.io

这是一个简单的例子

public class LogTailTest {

/**
* TailerListener implementation.
*/
static public class ShowLinesListener extends TailerListenerAdapter {
    @Override
    public void handle(String line) {
        System.out.println(line);
    }
}

public static void main(String args[]) {

    TailerListener listener  = new ShowLinesListener();
    File file = new File("./test.log");

    Tailer tailer = new Tailer(file, listener, 1000);
    tailer.run();

    try {
        Thread.sleep(100000);
    } catch(InterruptedException ex) {
        Thread.currentThread().interrupt();
    }

    tailer.stop();
}

}