I have a java ee application where I use a servlet to print a log file created with log4j. When reading log files you are usually looking for the last log line and therefore the servlet would be much more useful if it printed the log file in reverse order. My actual code is:
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(); }
The implementations I've found in the internet involve using a StringBuffer and loading all the file before printing, isn't there a code light way of seeking to the end of the file and reading the content till the start of the file?
An efficient solution to read a file in reverse order is, Start reading the file from last and continue till the start of the file i.e. in reverse order. As soon as it encounter any '\n' then it means, a complete line is read.
Strings can be reversed using slicing. To reverse a string, we simply create a slice that starts with the length of the string, and ends at index 0. The slice statement means start at string length, end at position 0, move with the step -1 (or one step backward).
Use readlines() to Read the range of line from the File The readlines() method reads all lines from a file and stores it in a list. You can use an index number as a line number to extract a set of lines from it. This is the most straightforward way to read a specific line from a file in Python.
Use the up arrow key to go backwards line by line or ctl+b to go page by page. This not only goes to the end of the file, it waits for additional output at the end, like tail -f . If this isn't what you want, you should use +G instead. and you can stop waiting for additional output by pressing CTRL+C.
[EDIT]
By request, I am prepending this answer with the sentiment of a later comment: If you need this behavior frequently, a "more appropriate" solution is probably to move your logs from text files to database tables with DBAppender (part of log4j 2). Then you could simply query for latest entries.
[/EDIT]
I would probably approach this slightly differently than the answers listed.
(1) Create a subclass of Writer
that writes the encoded bytes of each character in reverse order:
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) Create a subclass of log4j WriterAppender
whose createWriter
method would be overridden to create an instance of ReverseOutputStreamWriter
.
(3) Create a subclass of log4j Layout
whose format
method returns the log string in reverse character order:
public class ReversePatternLayout extends PatternLayout { // constructors public String format(LoggingEvent event) { return new StringBuilder(super.format(event)).reverse().toString(); } }
(4) Modify my logging configuration file to send log messages to both the "normal" log file and a "reverse" log file. The "reverse" log file would contain the same log messages as the "normal" log file, but each message would be written backwards. (Note that the encoding of the "reverse" log file would not necessarily conform to UTF-8, or even any character encoding.)
(5) Create a subclass of InputStream
that wraps an instance of RandomAccessFile
in order to read the bytes of a file in reverse order:
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 }
Now if I want to read the entries of the "normal" log file in reverse order, I just need to create an instance of ReverseFileInputStream
, giving it the "revere" log file.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With