java - 在 Java 中实时读取大型日志文件
问题描述
在 Java 8 中我可以使用什么来实时读取日志文件?我阅读博客以了解 BufferedReader 是一个很好的阅读选择。我在下面试过:
BufferedReader reader = new
BufferedReader(new
InputStreamReader(inputStream));
String line;
while(true) {
line = reader.readLine(); // blocks until next line
available
// do whatever You want with line
}
但是,无论文件是否更新,它都会保持打印 null 。知道可能出了什么问题。
还有其他选择吗?
详细信息如下: 我正在尝试在 Java 8 或更高版本中创建一个实用程序,我需要在其中实时读取应用程序的日志文件(因为实时事务正在发生并打印在日志中)。
我可以像在 sme 服务器上一样访问日志文件,所以这不是问题。
所以一些细节如下->我不想轮询日志文件的更改,我想保持桥打开以在“while true”循环中读取日志文件。所以理想情况下,如果没有新行被打印,我想阻止我的读者。
-> 我不想一直将文件的全部内容存储在内存中,因为我希望它具有内存效率。
-> 我的代码将作为一个单独的应用程序运行以读取另一个应用程序的日志文件。
-> 我的代码的唯一工作是读取日志,匹配模式,如果匹配,则发送带有日志内容的消息。
请让我知道是否有任何细节模棱两可。
有任何帮助,谢谢。
解决方案
为此,您inputStream
必须阻止直到有新数据可用,而标准FileInputStream
在到达文件末尾时不会这样做。
我想,你初始化inputStream
为new FileInputStream("my-logfile.log");
. 此流将仅读取到日志文件的当前结尾并向BufferedReader
. 这反过来将通过null
从readLine()
.
看看实用程序org.apache.commons.io.input.Tailer
。这允许编写像 Unix 实用程序这样的程序tail -f
。
为了使您的代码正常工作,您必须使用可以使用 a 实现的“无限”输入流,RandomAccessFile
如下例所示:
package test;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.RandomAccessFile;
import java.nio.file.Files;
import java.nio.file.StandardOpenOption;
public class TestRead {
public static void main(String[] args) throws IOException, InterruptedException {
File logFile = new File("my-log.log");
// Make sure to start form a defined condition.
logFile.delete();
try (OutputStream out = Files.newOutputStream(logFile.toPath(), StandardOpenOption.CREATE)) {
// Just create an empty file to append later on.
}
Thread analyzer = Thread.currentThread();
// Simulate log file writing.
new Thread() {
@Override
public void run() {
try {
for (int n = 0; n < 16; n++) {
try (OutputStream out = Files.newOutputStream(logFile.toPath(), StandardOpenOption.APPEND)) {
PrintWriter printer = new PrintWriter(out);
String line = "Line " + n;
printer.println(line);
printer.flush();
System.out.println("wrote: " + line);
}
Thread.sleep(1000);
}
} catch (Exception ex) {
ex.printStackTrace();
} finally {
analyzer.interrupt();
}
}
}.start();
// The original code reading the log file.
try (InputStream inputStream = new InfiniteInputStream(logFile);) {
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream), 8);
String line;
while (true) {
line = reader.readLine();
if (line == null) {
System.out.println("End-of-file.");
break;
}
System.out.println("read: " + line);
}
}
}
public static class InfiniteInputStream extends InputStream {
private final RandomAccessFile _in;
public InfiniteInputStream(File file) throws IOException {
_in = new RandomAccessFile(file, "r");
}
@Override
public int read(byte[] b, int off, int len) throws IOException {
if (b == null) {
throw new NullPointerException();
} else if (off < 0 || len < 0 || len > b.length - off) {
throw new IndexOutOfBoundsException();
} else if (len == 0) {
return 0;
}
int c = read();
if (c == -1) {
return -1;
}
b[off] = (byte)c;
int i = 1;
try {
for (; i < len ; i++) {
c = readDirect();
if (c == -1) {
break;
}
b[off + i] = (byte)c;
}
} catch (IOException ee) {
}
return i;
}
@Override
public int read() throws IOException {
int result;
while ((result = readDirect()) < 0) {
// Poll until more data becomes available.
try {
Thread.sleep(500);
} catch (InterruptedException ex) {
return -1;
}
}
return result;
}
private int readDirect() throws IOException {
return _in.read();
}
}
}
推荐阅读
- sql-server-2017 - 数据分析查看器中的数据类型参数不能为空
- here-api - ApplicationError:请求中指定的 LinkId 不可用
- python - 如何在 Gurobi python 界面中创建二进制变量?
- python - 我可以在 Python Markdown 中将标签列入白名单吗?
- php - Laravel PHPUnit 测试抛出禁止错误
- reactjs - 开发服务器返回响应错误码:500\React Native
- javascript - 使用 React 和 JQuery 从文件中绘制 SVG 的问题
- javascript - 我想获取具有相同字段名称的对象中的所有值并存储在数组中
- jenkins - Jenkins > Blue Ocean > 从最新提交构建
- google-cloud-platform - 使用 fstab 和 gcsfuse 在存储桶名称前自动添加斜线