提问人:Gary 提问时间:2/18/2009 最后编辑:ChirloGary 更新时间:12/2/2016 访问量:81609
unix/linux “tail -f” 的 Java IO 实现
Java IO implementation of unix/linux "tail -f"
问:
我想知道使用什么技术和/或库来实现 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
答:
能够继续读取文件,并等待文件有更多更新,这应该不难在代码中完成。下面是一些伪代码:
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 中,以便您可以休眠它而不会影响应用程序的任何其他区域。您可能希望在 setter 中公开,以便您的主类/应用程序的其他部分可以安全地关闭线程,而不会出现任何其他麻烦,只需调用或类似的东西即可。keepReading
stopReading()
评论
这里有一个小故事,你可以用它来作为指针:
出于同样的原因,我在工作中编写了 TailingInputStream 代码。它基本上使用 File 并按需刷新其内容,如果它发生了重大变化(4kB 内存标记 IIRC),则根据内部缓冲区进行检查,然后执行尾部 -f 的作用。是的,有点骇人听闻,但它运行良好,不会惹恼 Threads 或类似的东西——它至少可以追溯到 1.4.2。
也就是说,它比 ReverseInputStream 容易得多,后者从文件的末尾到开始,如果文件动态更新,它就不会死......
检查 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();
}
评论
如果你的代码只需要在Unix系统上运行,你也许可以逃脱直接调用。tail -f
作为一个更复杂的替代方案,你可以看看 GNU tail 的实现,并将其移植到 Java 上。(不过,我不确定这是否会让你的代码成为衍生作品。
评论
tail -f
我前段时间在 Scala 中构建了一个简短的“tail -f”实现:tailf。它还负责文件轮换,您可以定义自己的逻辑,当它到达 EOF 或发现文件已被重命名时该做什么。
您可以看一下并将其移植到 Java 上,因为实际上那里没有什么复杂的。几点说明:主文件是 Tail.scala,基本上它定义了 FollowingInputStream
,它负责 EOF/rename 和 follow
方法,该方法包装成 .因此,一旦结束,就会创建一个来自一个和另一个元素的下一个请求。FollowingInputStream
SequenceInputStream
FollowingInputStream
SequenceInputStream
Enumeration
FollowingInputStream
看看 Tailer 类的 Apache Commons 实现。它似乎也处理日志轮换。
评论
只是遇到了同样的问题 - 在这里找到了“最简单”的实现:Java Tail。
*很棒的东西 * - 准备生产;)
我希望代码引用不会丢弃一些许可证。
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)]");
}
}
}
我最近偶然发现了 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);
}
评论
我发现了这个不错的尾部实现。
作者 : amelandri
Souce 自: 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)]");
}
}
}
评论