一尘不染

以相反的顺序逐行读取文件

java

我有一个Java
ee应用程序,在该应用程序中,我使用servlet来打印使用log4j创建的日志文件。在读取日志文件时,通常会寻找最后一个日志行,因此,如果servlet以相反的顺序打印日志文件,则它会更加有用。我的实际代码是:

    response.setContentType("text");
    PrintWriter out = response.getWriter();
    try {
        FileReader logReader = new FileReader("logfile.log");
        try {
            BufferedReader buffer = new BufferedReader(logReader);
            for (String line = buffer.readLine(); line != null; line = buffer.readLine()) {
                out.println(line);
            }
        } finally {
            logReader.close();
        }
    } finally {
        out.close();
    }

我在互联网上找到的实现涉及使用StringBuffer并在打印之前加载所有文件,难道没有找到找到文件结尾并读取内容直到文件开头的代码轻巧的方式吗?


阅读 250

收藏
2020-09-08

共1个答案

一尘不染

[编辑]

根据要求,我将在稍后的评论中添加此答案:如果您经常需要此行为,则“更合适的”解决方案可能是使用DBAppender将日志从文本文件移动到数据库表(log4j
2的一部分)。然后,您可以简单地查询最新条目。

[/编辑]

与列出的答案相比,我可能会略有不同。

(1)创建一个子类,Writer该子类以相反的顺序写入每个字符的编码字节:

public class ReverseOutputStreamWriter extends Writer {
    private OutputStream out;
    private Charset encoding;
    public ReverseOutputStreamWriter(OutputStream out, Charset encoding) {
        this.out = out;
        this.encoding = encoding;
    }
    public void write(int ch) throws IOException {
        byte[] buffer = this.encoding.encode(String.valueOf(ch)).array();
        // write the bytes in reverse order to this.out
    }
    // other overloaded methods
}

(2)创建log4j
WriterAppender的子类,该子类的createWriter方法将被覆盖以创建的实例ReverseOutputStreamWriter

(3)创建一个log4j Layout的子类,其format方法以相反的字符顺序返回日志字符串:

public class ReversePatternLayout extends PatternLayout {
    // constructors
    public String format(LoggingEvent event) {
        return new StringBuilder(super.format(event)).reverse().toString();
    }
}

(4)修改我记录配置文件发送日志消息到 两个
“正常”的日志文件和“反向”的日志文件。“反向”日志文件将包含与“正常”日志文件相同的日志消息,但是每条消息将向后写入。(请注意,“反向”日志文件的编码不一定符合UTF-8甚至任何字符编码。)

(5)创建一个InputStream包装的实例的子类,RandomAccessFile以便以相反的顺序读取文件的字节:

public class ReverseFileInputStream extends InputStream {
    private RandomAccessFile in;
    private byte[] buffer;
    // The index of the next byte to read.
    private int bufferIndex;
    public ReverseFileInputStream(File file) {
        this.in = new RandomAccessFile(File, "r");
        this.buffer = new byte[4096];
        this.bufferIndex = this.buffer.length;
        this.in.seek(file.length());
    }
    public void populateBuffer() throws IOException {
        // record the old position
        // seek to a new, previous position
        // read from the new position to the old position into the buffer
        // reverse the buffer
    }
    public int read() throws IOException {
        if (this.bufferIndex == this.buffer.length) {
            populateBuffer();
            if (this.bufferIndex == this.buffer.length) {
                return -1;
            }
        }
        return this.buffer[this.bufferIndex++];
    }
    // other overridden methods
}

现在,如果我想以相反的顺序读取“正常”日志文件的条目,我只需要创建一个实例ReverseFileInputStream,将其赋予“
revere”日志文件。

2020-09-08