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();
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?
– Math
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.
– Bacco