首页 > 解决方案 > 在 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”循环中读取日志文件。所以理想情况下,如果没有新行被打印,我想阻止我的读者。

-> 我不想一直将文件的全部内容存储在内存中,因为我希望它具有内存效率。

-> 我的代码将作为一个单独的应用程序运行以读取另一个应用程序的日志文件。

-> 我的代码的唯一工作是读取日志,匹配模式,如果匹配,则发送带有日志内容的消息。

请让我知道是否有任何细节模棱两可。

有任何帮助,谢谢。

标签: javaperformanceio

解决方案


为此,您inputStream必须阻止直到有新数据可用,而标准FileInputStream在到达文件末尾时不会这样做。

我想,你初始化inputStreamnew FileInputStream("my-logfile.log");. 此流将仅读取到日志文件的当前结尾并向BufferedReader. 这反过来将通过nullreadLine().

看看实用程序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();
        }

    }
}

推荐阅读