unix/linux“tail -f”的Java IO实现
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/557844/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Java IO implementation of unix/linux "tail -f"
提问by Gary
I'm wondering what techniques and/or library to use to implement the functionality of the linux command "tail -f ". I'm essentially looking for a drop in add-on/replacement for java.io.FileReader
. Client code could look something like this:
我想知道使用什么技术和/或库来实现 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
}
The missing piece is a reasonable implementation of TailFileReader
. It should be able to read parts of the file that exist before the file is opened as well as the lines that are added.
缺少的部分是TailFileReader
. 它应该能够读取文件打开之前存在的文件部分以及添加的行。
采纳答案by matt b
The ability to continue to read a file, and wait around until the file has some more updates for you shouldn't be that hard to accomplish in code yourself. Here's some pseudo-code:
继续读取文件并等待文件有更多更新的能力应该不难自己在代码中实现。这是一些伪代码:
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
}
}
I would assume that you would want to put this type of functionality in its own Thread, so that you can sleep it and not affect any other areas of your application. You would want to expose keepReading
in a setter so that your main class / other parts of the application can safely shut the thread down without any other headaches, simply by calling stopReading()
or something similar.
我假设您希望将这种类型的功能放在它自己的线程中,这样您就可以休眠它而不会影响应用程序的任何其他区域。您可能希望keepReading
在 setter 中公开,以便您的主类/应用程序的其他部分可以安全地关闭线程,而无需任何其他麻烦,只需调用stopReading()
或类似的方法即可。
回答by Esko
Here's a short story which you could use as a pointer:
这是一个可以用作指针的小故事:
I've coded TailingInputStream at work for the very same reason. It basically uses File and refreshed its contents on demand and checked against internal buffer if it has changed significantly (4kB memory stamp IIRC) and then did what the tail -f does. A bit hacky, yes, but it works perfectly and doesn't mess with Threads or anything fancy like that - it's compatible all the way back to 1.4.2 at least.
出于同样的原因,我在工作中对 TailingInputStream 进行了编码。它基本上使用 File 并按需刷新其内容,并检查内部缓冲区是否发生重大变化(4kB 内存标记 IIRC),然后执行 tail -f 所做的操作。有点 hacky,是的,但它工作得很好并且不会与 Threads 或任何类似的东西混淆 - 它至少一直兼容到 1.4.2。
That said, it was a lot easier to do than ReverseInputStream which went from file's end to start and didn't die if the file was updated on the fly...
也就是说,它比 ReverseInputStream 容易得多,它从文件的末尾到开始,并且如果文件被动态更新也不会死......
回答by aldrinleal
Check JLogTailer, which does this logic.
检查JLogTailer,它执行此逻辑。
The main point in the code is:
代码中的要点是:
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();
}
回答by Daniel Werner
If your code only ever will have to run on Unix systems, you may be able to get away with just shelling out and calling tail -f
directly.
如果您的代码只需要在 Unix 系统上运行,那么您可以tail -f
直接退出并直接调用。
As a more involved alternative, you could take a look at the implementation of GNU tail and port that over to Java. (I'm not sure whether this wouldn't already make your code a derivative work, though.)
作为更复杂的替代方案,您可以查看 GNU tail 的实现并将其移植到 Java。(不过,我不确定这是否不会使您的代码成为衍生作品。)
回答by Alexander Azarov
I've built a short implementation of "tail -f" in Scala some time ago: tailf. It takes care of file rotation as well and you may define your own logic what to do when it reaches EOF or finds the file has been renamed.
前段时间我在 Scala 中构建了一个简短的“tail -f”实现:tailf。它也负责文件轮换,您可以定义自己的逻辑,当它到达 EOF 或发现文件已被重命名时要做什么。
You may take a look and port it to Java, since actually there is nothing complex in there. Few notes: the main file is Tail.scalaand basically it defines FollowingInputStream
which takes care of EOF/rename and follow
method, which wraps FollowingInputStream
into an unbounded enumeration in SequenceInputStream
. So, as soon as FollowingInputStream
ends, SequenceInputStream
requests next element from an Enumeration
and another FollowingInputStream
gets created.
您可以查看一下并将其移植到 Java,因为实际上那里没有什么复杂的。几个注意事项:主文件是Tail.scala并且基本上它定义了FollowingInputStream
哪个负责 EOF/重命名和follow
方法,它包含FollowingInputStream
在.scala 中的无限枚举中SequenceInputStream
。因此,一旦FollowingInputStream
结束,就SequenceInputStream
从一个请求下一个元素,Enumeration
然后FollowingInputStream
创建另一个。
回答by Chetan Sastry
回答by ViPup
Just was faced with the same issue - found the "simplest" implementation here: Java Tail.
刚刚面临同样的问题 - 在这里找到了“最简单”的实现:Java Tail。
*Great stuff *- ready for production ;)
*好东西 *- 准备生产;)
I hope the code-citation will not drop some license.
我希望代码引用不会放弃一些许可证。
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)]");
}
}
}
回答by cheffe
I stumbled recently over rxjava-file, It is an extension of RxJava. In contrast to the other solutions this makes use of Java's NIO.
我最近偶然发现了rxjava-file,它是RxJava的扩展。与其他解决方案相比,这使用了 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);
}
回答by Mahesh K
I found this nice tail implementation.
我发现了这个不错的尾部实现。
Author : amelandri
添加一名作者
Souce from : https://gist.github.com/amelandri/1376896
来源: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)]");
}
}
}