unix / linux的Java IO实现“tail -f”
我想知道用什么技术和/或库来实现linux命令“tail -f”的function。 我本质上是寻找在java.io.FileReader
插件/replace下降。 客户端代码可能如下所示:
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 }
缺less的一部分是TailFileReader
的合理实现。 它应该能够读取文件在打开文件之前存在的部分以及添加的行。
能够继续读取文件,并等待,直到文件有更多的更新,你不应该很难完成自己的代码。 这是一些伪代码:
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 } }
我会假设你想把这种types的function放在它自己的Thread中,这样你就可以睡觉,而不会影响你的应用程序的其他任何区域。 你会想在一个setter中公开keepReading
,这样你的主要类/应用程序的其他部分就可以安全地closures线程,而不用stopReading()
任何其他麻烦,只需调用stopReading()
或类似的东西。
看一看Apache Commons实现的Tailer类。 它似乎也处理日志的旋转。
检查这个逻辑的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中构build了一个简短的“tail -f”实现: tailf 。 它也负责文件的旋转,你可以定义自己的逻辑,当它到达EOF或者发现文件已经被重命名时,该怎么做。
您可以看一下并将其移植到Java,因为实际上这里没有任何复杂的东西。 几个注意事项:主要文件是Tail.scala ,基本上它定义了FollowInputStream ,它负责EOF /重命名并follow
方法,该方法将FollowingInputStream
包装到SequenceInputStream
一个无限枚举中。 因此,只要FollowingInputStream
结束, SequenceInputStream
将从Enumeration
请求下一个元素,并创build另一个FollowingInputStream
。
我最近偶然发现了rxjava文件 ,它是RxJava的扩展。 与其他解决scheme相比,这使用了Java的NIO。
import rx.Observable; import rx.functions.Action1; import com.github.davidmoten.rx.FileObservable; // ... class definition omitted public void tailLogFile() throws InterruptedException { Observable<String> tailer = FileObservable.tailer() .file("application.log") // absolute path .tailText(); tailer.subscribe( new Action1<String>() { @Override public void call(String line) { System.out.println("you got line: " + line); } }, new Action1<Throwable>() { @Override public void call(Throwable e) { System.out.println("you got error: " + e); e.printStackTrace(); } } ); // this solution operates threaded, so something // is required that prevents premature termination Thread.sleep(120000); }
这是一个你可以用作指针的简短故事:
我在工作中编写TailingInputStream的原因也是一样的。 它基本上使用文件并刷新其内容的需求,并检查内部缓冲区,如果它发生了显着变化(4kB内存邮票IIRC),然后做什么尾-f做。 有点怪异,是的,但它完美的工作,不会混乱线程或任何像这样的幻想 – 至less兼容1.4.2。
也就是说,这比从文件结尾到文件开头的ReverseInputStream要容易得多,如果文件被更新的话就不会死掉。
如果你的代码只能运行在Unix系统上,那么你可以直接脱壳并直接调用tail -f
。
作为一个更为复杂的select,你可以看看GNU tail和port的实现。 (不过,我不确定这是否会让你的代码成为一个派生工作)。
刚刚面对同样的问题 – 在这里find了“最简单”的实现: Java尾巴 。
* 伟大的东西* – 准备生产;)
我希望代码引用不会放弃一些许可证。
import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; /** * Java implementation of the Unix tail command * * @param args[0] File name * @param args[1] Update time (seconds). Optional. Default value is 1 second * * @author Luigi Viggiano (original author) http://it.newinstance.it/2005/11/19/listening-changes-on-a-text-file-unix-tail-implementation-with-java/ * @author Alessandro Melandri (modified by) * */ public class Tail { static long sleepTime = 1000; public static void main(String[] args) throws IOException { if (args.length > 0){ if (args.length > 1) sleepTime = Long.parseLong(args[1]) * 1000; BufferedReader input = new BufferedReader(new FileReader(args[0])); String currentLine = null; while (true) { if ((currentLine = input.readLine()) != null) { System.out.println(currentLine); continue; } try { Thread.sleep(sleepTime); } catch (InterruptedException e) { Thread.currentThread().interrupt(); break; } } input.close(); } else { System.out.println("Missing parameter!\nUsage: java JavaTail fileName [updateTime (Seconds. default to 1 second)]"); } } }
我发现这个漂亮的尾巴实现。
作者:amelandri
源自: https ://gist.github.com/amelandri/1376896
import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; /** * Java implementation of the Unix tail command * * @param args[0] File name * @param args[1] Update time (seconds). Optional. Default value is 1 second * * @author Luigi Viggiano (original author) http://it.newinstance.it/2005/11/19/listening-changes-on-a-text-file-unix-tail-implementation-with-java/ * @author Alessandro Melandri (modified by) * */ public class Tail { static long sleepTime = 1000; public static void main(String[] args) throws IOException { if (args.length > 0){ if (args.length > 1) sleepTime = Long.parseLong(args[1]) * 1000; BufferedReader input = new BufferedReader(new FileReader(args[0])); String currentLine = null; while (true) { if ((currentLine = input.readLine()) != null) { System.out.println(currentLine); continue; } try { Thread.sleep(sleepTime); } catch (InterruptedException e) { Thread.currentThread().interrupt(); break; } } input.close(); } else { System.out.println("Missing parameter!\nUsage: java JavaTail fileName [updateTime (Seconds. default to 1 second)]"); } } }