Tuve el mismo problema que el descrito aquí. Quiero ver las líneas en el archivo en orden inverso, desde el final hasta el inicio (El comando unix tac lo hará).
Sin embargo, mis archivos de entrada son bastante grandes, por lo que leer todo el archivo en la memoria, como en los otros ejemplos no era realmente una opción viable para mí.
A continuación se muestra la clase que se me ocurrió, utiliza RandomAccessFile
, pero no necesita ningún búfer, ya que solo conserva los punteros del archivo y funciona con los métodos estándar InputStream
.
Funciona para mis casos, y archivos vacíos y algunas otras cosas que he probado. Ahora no tengo caracteres Unicode ni nada sofisticado, pero siempre que las líneas estén delimitadas por LF, e incluso si tienen un LF + CR debería funcionar.
Uso básico es:
in = new BufferedReader (new InputStreamReader (new ReverseLineInputStream(file)));
while(true) {
String line = in.readLine();
if (line == null) {
break;
}
System.out.println("X:" + line);
}
Aquí es la fuente principal:
package www.kosoft.util;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.RandomAccessFile;
public 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();
}
}
}
¿Cuál es el propósito de leer el archivo de principio a fin? – adatapost
pregunta se contesta mismo tipo http://stackoverflow.com/questions/6011345/read-a-file-line-by-line-in-reverse-order Salida. – Zlatan
¿no puedes simplemente leer el archivo y usar el método reverse() en StringBuilder? – asgs