Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Read a file line by line in reverse order

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?

like image 406
eliocs Avatar asked May 15 '11 21:05

eliocs


People also ask

How do you read a file in reverse order?

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.

How do you reverse a line in Python?

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).

How do I start reading a file from a specific line?

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.

How do I read a file from the bottom?

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.


1 Answers

[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.

like image 50
Nathan Ryan Avatar answered Oct 06 '22 00:10

Nathan Ryan