我想知道用什么技术和/或库来实现linux命令"tail -f"的功能.我基本上是在寻找一个附加/替换的下降java.io.FileReader
.客户端代码可能如下所示:
TailFileReader lft = new TailFileReader("application.log"); BufferedReader br = new BufferedReader(lft); String line; try { while (true) { line= br.readLine(); // do something interesting with line } } catch (IOException e) { // barf }
缺失的部分是合理的实施TailFileReader
.它应该能够读取文件打开前存在的文件部分以及添加的行.
看看Apache Commons实现的Tailer类.它似乎也处理日志轮换.
能够继续读取文件,并等待文件为您提供更多更新,这本身并不难以在代码中完成.这是一些伪代码:
BufferedReader br = new BufferedReader(...); String line; while (keepReading) { line = reader.readLine(); if (line == null) { //wait until there is more of the file for us to read Thread.sleep(1000); } else { //do something interesting with the line } }
我假设您希望将此类功能放在其自己的Thread中,以便您可以将其休眠并且不会影响应用程序的任何其他区域.您可能希望keepReading
在setter中公开,以便您的主类/应用程序的其他部分可以安全地关闭线程而不会有任何其他麻烦,只需通过调用stopReading()
或类似的东西.
检查JLogTailer,它执行此逻辑.
代码中的要点是:
public void run() { try { while (_running) { Thread.sleep(_updateInterval); long len = _file.length(); if (len < _filePointer) { // Log must have been jibbled or deleted. this.appendMessage("Log file was reset. Restarting logging from start of file."); _filePointer = len; } else if (len > _filePointer) { // File must have had something added to it! RandomAccessFile raf = new RandomAccessFile(_file, "r"); raf.seek(_filePointer); String line = null; while ((line = raf.readLine()) != null) { this.appendLine(line); } _filePointer = raf.getFilePointer(); raf.close(); } } } catch (Exception e) { this.appendMessage("Fatal error reading log file, log tailing has stopped."); } // dispose(); }
我前段时间在Scala中构建了一个简短的"tail -f"实现:tailf.它还负责文件轮换,您可以定义自己的逻辑,当它到达EOF时发生了什么,或者发现文件已被重命名.
您可以查看并将其移植到Java,因为实际上没有任何复杂的东西.几个注意事项:主文件是Tail.scala,基本上它定义了FollowingInputStream
哪个处理EOF/rename和follow
方法,它包含FollowingInputStream
在一个无限的枚举中SequenceInputStream
.因此,一旦FollowingInputStream
结束,就会创建SequenceInputStream
请求来自Enumeration
另一个元素的下一个元素FollowingInputStream
.