Read a file line by line in reverse order in Java

We will write a java program that reads a file line by line in reverse order i.e., from end to start.

Read a file line by line in reverse order in Java

In this post, we will go over below steps to write a Java program to read a file line by line in reverse order.

  • We write Java code that reads the file from end to start.
  • We will read the velocitybytes.log file which has some data.
  • We will test the code that we have written.

Java Code:

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

public class ReverseLineReader {

	private static final int BUFFER_SIZE = 8192;
	private final FileChannel channel;
	private final String encoding;
	private long filePos;
	private ByteBuffer buffer;
	private int bufferPos;
	private ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
	private final RandomAccessFile raf;
	// private final byte lastLineBreak = '\n';


	public ReverseLineReader(File file) throws IOException {
		this(file, null);
	}

	public ReverseLineReader(File file, String encoding) throws IOException {
		raf = new RandomAccessFile(file, "r");
		channel = raf.getChannel();
		filePos = raf.length();
		this.encoding = encoding;
	}

	public void close() throws IOException {
		raf.close();
	}

	public String readLine() throws IOException {
		byte c;
		while (true) {
			if (bufferPos < 0) {
				if (filePos == 0) {
					if (byteArrayOutputStream == null) {
						return null;
					}
					String line = bufferToString();
					byteArrayOutputStream = null;
					return line;
				}

				long start = Math.max(filePos - BUFFER_SIZE, 0);
				long end = filePos;
				long len = end - start;

				buffer = channel.map(FileChannel.MapMode.READ_ONLY, start, len);
				bufferPos = (int) len;
				filePos = start;

				// Ignore Empty New Lines
				c = buffer.get(--bufferPos);
				if (c == '\r' || c == '\n')
					while (bufferPos > 0 && (c == '\r' || c == '\n')) {
						bufferPos--;
						c = buffer.get(bufferPos);
					}
				if (!(c == '\r' || c == '\n'))
					bufferPos++;// IS THE NEW LINE
			}

			/*
			 * This will ignore all blank new lines.
			 */
			while (bufferPos-- > 0) {
				c = buffer.get(bufferPos);
				if (c == '\r' || c == '\n') {
					// skip \r\n
					while (bufferPos > 0 && (c == '\r' || c == '\n')) {
						c = buffer.get(--bufferPos);
					}
					// restore cursor
					if (!(c == '\r' || c == '\n'))
						bufferPos++;// IS THE NEW Line
					return bufferToString();
				}
				byteArrayOutputStream.write(c);
			}

			/*
			 *  If you don't want to ignore new line and would like
			 *  to print new line too then use below code
			 *  and comment out above while loop

			while (bufPos-- > 0) {
				byte c1 = buf.get(bufPos);
				if (c1 == '\r' || c1 == '\n') {
					if (c1 != lastLineBreak) {
						lastLineBreak = c1;
						continue;
					}
					lastLineBreak = c1;
					return bufToString();
				}
				byteArrayOutputStream.write(c1);
			}
			*/

		}
	}

	private String bufferToString() throws UnsupportedEncodingException {
		if (byteArrayOutputStream.size() == 0) {
			return "";
		}

		byte[] bytes = byteArrayOutputStream.toByteArray();
		for (int i = 0; i < bytes.length / 2; i++) {
			byte t = bytes[i];
			bytes[i] = bytes[bytes.length - i - 1];
			bytes[bytes.length - i - 1] = t;
		}

		byteArrayOutputStream.reset();
		if (encoding != null)
			return new String(bytes, encoding);
		else
			return new String(bytes);
	}
}

Read a file:

Create a file (.txt or .log etc.,) that has some data.

// velocitybytes.log
Velocity Bytes
Java
Spring
React

Let's test:

import java.io.File;
import java.io.IOException;

public class ReverseLineReaderMain {

    public static void main(String[] args) {

        try {
            File file = new File("C:\\velocitybytes.log");
            ReverseLineReader reverseLineReader = new ReverseLineReader(file, "UTF-8");
            String line;

            while ((line = reverseLineReader.readLine()) != null) {
                System.out.println(line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

As expected, the following is the output:

React
Spring
Java
Velocity Bytes

Thanks for coming!