按相反顺序逐行读取文件

eli*_*ocs 28 java text log4j file

我有一个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();
    }
Run Code Online (Sandbox Code Playgroud)

我在互联网上找到的实现涉及使用StringBuffer并在打印之前加载所有文件,是不是有代码轻量级方式寻找到文件的末尾并读取内容直到文件的开头?

Nat*_*yan 11

[编辑]

根据请求,我在前面的评论中提到了这个答案:如果您经常需要这种行为,"更合适"的解决方案可能是使用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
}
Run Code Online (Sandbox Code Playgroud)

(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();
    }
}
Run Code Online (Sandbox Code Playgroud)

(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
}
Run Code Online (Sandbox Code Playgroud)

现在,如果我想以相反的顺序读取"普通"日志文件的条目,我只需要创建一个实例ReverseFileInputStream,给它"崇敬"日志文件.

  • @eliocs:绝对了解简单的解决方案而不是复制日志数据.如果您经常需要这种行为,"更合适"的解决方案可能是使用`DBAppender`(log4j 2的一部分)将日志从文本文件移动到数据库表.然后你可以简单地查询最新的条目. (4认同)

Cha*_*enu 8

这是一个老问题.我也想做同样的事情,经过一些搜索发现apache commons-io中有一个类来实现这个目的:

org.apache.commons.io.input.ReversedLinesFileReader