Reverse reading of files

2

My goal is to read a file (line by line), however, starting at the end of the file (last line) to the beginning (first line).

Could anyone give you a possible idea of doing this?

I was using RandomAcessFile with the intention of using seek to the end of the file and going back, but it did not work very well.

    
asked by anonymous 23.09.2015 / 13:55

2 answers

1

Files#readAllLines returns you a list of all the lines in the file. Then you can use Collections.reverse to reverse the order of this list:

List<String> linhas = Files.readAllLines(Paths.get("foo/bar.txt"));
Collections.reverse(linhas);

You can use List#get to get each line of the file later: linhas.get(0); (which would return the first line) will return the last, and so on ...

Running on Repl.it

    
26.06.2016 / 00:52
0

Here's the implementation:

 /**
 * Input stream utilizado para ler um arquivo em ordem reversa
 * http://stackoverflow.com/questions/8664705/how-to-read-file-from-end-to-start
 * -in-reverse-order-in-java
 *
 *
 */
class ReverseLineInputStream extends InputStream {

    RandomAccessFile in;

    long currentLineStart = -1;
    long currentLineEnd = -1;
    long currentPos = -1;
    long lastPosInFile = -1;

    public ReverseLineInputStream(File file) throws FileNotFoundException {
        in = new RandomAccessFile(file, "r");
        currentLineStart = file.length();
        currentLineEnd = file.length();
        lastPosInFile = file.length() - 1;
        currentPos = currentLineEnd;
    }

    public void findPrevLine() throws IOException {

        currentLineEnd = currentLineStart;

        // There are no more lines, since we are at the beginning of the file
        // and no lines.
        if (currentLineEnd == 0) {
            currentLineEnd = -1;
            currentLineStart = -1;
            currentPos = -1;
            return;
        }

        long filePointer = currentLineStart - 1;

        while (true) {
            filePointer--;

            // we are at start of file so this is the first line in the file.
            if (filePointer < 0) {
                break;
            }

            in.seek(filePointer);
            int readByte = in.readByte();

            // We ignore last LF in file. search back to find the previous LF.
            if (readByte == 0xA && filePointer != lastPosInFile) {
                break;
            }
        }
        // we want to start at pointer +1 so we are after the LF we found or at
        // 0 the start of the file.
        currentLineStart = filePointer + 1;
        currentPos = currentLineStart;
    }

    public int read() throws IOException {

        if (currentPos < currentLineEnd) {
            in.seek(currentPos++);
            int readByte = in.readByte();
            return readByte;

        } else if (currentPos < 0) {
            return -1;
        } else {
            findPrevLine();
            return read();
        }
    }

    @Override
    public void close() throws IOException {
        super.close();
        in.close();
    }
}

Using it:

ReverseLineInputStream reverseLineInputStream = new RverseLineInputStream(file);
InputStreamReader inputStreamReader = new InputStreamReader(reverseLineInputStream);
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
String readLine = bufferedReader.readLine();
    
23.09.2015 / 14:57