Read files in reverse way

Asked

Viewed 971 times

2

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

One could give a possible idea of performing this procedure?

Was using RandomAcessFile in order to use the seek to the end of the file and go back, but it did not work very well.

  • 1

    It’s possible, but I think it’s going to be a huge scam. Do you have the need to do it this way? Because the ideal would be for you to read the entire file and then go around picking up the lines backwards. Take a look at this topic: How to rewind the file pointer correctly in Java?

  • 1

    If they are very large files, and variable length lines, I would suggest a "read" forward to index the lines and position, and use Seek with the index ready on the way back. There are legitimate cases for this, in situations where the file would not fit all in memory without performance penalty and the processing line by line really have to be reversed. But there’s a good chance that’s not your specific case. Another output for similar situation, is to read the file in fixed blocks, for example 8K in 8K, from the end pro start, and you scan the breaks of the lines in each block.

2 answers

1

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

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

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

Running on Repl.it

0

Here is 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 him:

ReverseLineInputStream reverseLineInputStream = new RverseLineInputStream(file);
InputStreamReader inputStreamReader = new InputStreamReader(reverseLineInputStream);
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
String readLine = bufferedReader.readLine();
  • 4

    Enter reference: http://stackoverflow.com/a/11665098/1964435 If it is possible to translate the explanations into English, it would be good.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.