¿Cuál es la forma más rápida y eficiente de leer la última línea de texto de un archivo [muy, muy grande] en Java?¿Leyó rápidamente la última línea de un archivo de texto?
Respuesta
Eche un vistazo a mi respuesta a un similar question for C#. El código sería bastante similar, aunque el soporte de codificación es algo diferente en Java.
Básicamente no es algo terriblemente fácil de hacer en general. Como señala MSalter, UTF-8 hace que sea fácil detectar \r
o \n
ya que la representación UTF-8 de esos caracteres es igual a ASCII, y esos bytes no ocurrirán en caracteres de múltiples bytes.
Así que, básicamente, tome un buffer de (digamos) 2K, y lea progresivamente hacia atrás (salte a 2K antes que antes, lea los próximos 2K) verificando la terminación de una línea. Luego omita exactamente el lugar correcto en la secuencia, cree un InputStreamReader
en la parte superior y un BufferedReader
encima de eso. Entonces simplemente llame al BufferedReader.readLine()
.
En C#, usted debe ser capaz de establecer la posición de la corriente:
Desde: http://bytes.com/groups/net-c/269090-streamreader-read-last-line-text-file
using(FileStream fs = File.OpenRead("c:\\file.dat"))
{
using(StreamReader sr = new StreamReader(fs))
{
sr.BaseStream.Position = fs.Length - 4;
if(sr.ReadToEnd() == "DONE")
// match
}
}
En FileInputStream de Java (en el que se basa FileReader), no puede establecer la posición; solo puede saltar hacia adelante, lo que probablemente no lea las partes que salteó, pero sigue siendo una operación unidireccional y por lo tanto no adecuada para buscar un salto de línea en un desplazamiento desconocido desde el final. –
Bueno ... Intenté: P – rball
Puede usar mark() para evitar ese problema, dependiendo de lo que sea la corriente markLimit(). –
Usando FileReader o FileInputStream no funcionará - Vas a tener que utilizar FileChannel o RandomAccessFile para recorrer el archivo hacia atrás desde el final. Las codificaciones serán un problema, como dijo Jon.
Tenga en cuenta que el rendimiento de RandomAccessFile es una mierda para operaciones individuales, por lo que las lecturas de tamaño razonables se realizan en un búfer. –
A continuación se muestran dos funciones, una que devuelve la última línea no en blanco de un archivo sin cargar o recorrer el archivo completo, y la otra que devuelve las últimas N líneas del archivo sin recorrer todo el archivo:
Lo que hace la cola es acercar directamente al último carácter del archivo, luego retrocede, carácter por carácter, grabando lo que ve hasta que encuentra un salto de línea. Una vez que encuentra un salto de línea, se rompe el ciclo. Invierte lo que se grabó y lo arroja a una cadena y regresa. 0xA es la nueva línea y 0xD es el retorno de carro.
Si sus terminaciones de línea son \r\n
o crlf
o alguna otra "nueva línea de estilo de nueva línea doble", tendrá que especificar n * 2 líneas para obtener las últimas n líneas porque cuenta 2 líneas para cada línea.
public String tail(File file) {
RandomAccessFile fileHandler = null;
try {
fileHandler = new RandomAccessFile(file, "r");
long fileLength = fileHandler.length() - 1;
StringBuilder sb = new StringBuilder();
for(long filePointer = fileLength; filePointer != -1; filePointer--){
fileHandler.seek(filePointer);
int readByte = fileHandler.readByte();
if(readByte == 0xA) {
if(filePointer == fileLength) {
continue;
}
break;
} else if(readByte == 0xD) {
if(filePointer == fileLength - 1) {
continue;
}
break;
}
sb.append((char) readByte);
}
String lastLine = sb.reverse().toString();
return lastLine;
} catch(java.io.FileNotFoundException e) {
e.printStackTrace();
return null;
} catch(java.io.IOException e) {
e.printStackTrace();
return null;
} finally {
if (fileHandler != null)
try {
fileHandler.close();
} catch (IOException e) {
/* ignore */
}
}
}
Pero es probable que no desea que la última línea, que quieren que los últimos N líneas, a fin de utilizar esto en su lugar:
public String tail2(File file, int lines) {
java.io.RandomAccessFile fileHandler = null;
try {
fileHandler =
new java.io.RandomAccessFile(file, "r");
long fileLength = fileHandler.length() - 1;
StringBuilder sb = new StringBuilder();
int line = 0;
for(long filePointer = fileLength; filePointer != -1; filePointer--){
fileHandler.seek(filePointer);
int readByte = fileHandler.readByte();
if(readByte == 0xA) {
if (filePointer < fileLength) {
line = line + 1;
}
} else if(readByte == 0xD) {
if (filePointer < fileLength-1) {
line = line + 1;
}
}
if (line >= lines) {
break;
}
sb.append((char) readByte);
}
String lastLine = sb.reverse().toString();
return lastLine;
} catch(java.io.FileNotFoundException e) {
e.printStackTrace();
return null;
} catch(java.io.IOException e) {
e.printStackTrace();
return null;
}
finally {
if (fileHandler != null)
try {
fileHandler.close();
} catch (IOException e) {
}
}
}
invocar a los métodos anteriores de esta manera:
File file = new File("D:\\stuff\\huge.log");
System.out.println(tail(file));
System.out.println(tail2(file, 10));
Advertencia En la naturaleza al oeste de Unicode este código puede causar que la salida de esta función salga mal. Por ejemplo, "María" en lugar de "María". Los caracteres con hats, accents, Chinese characters etc. pueden hacer que la salida sea incorrecta porque los acentos se agregan como modificadores después del carácter. La inversión de caracteres compuestos cambia la naturaleza de la identidad del personaje en la reversión. Tendrá que hacer una batería completa de pruebas en todos los idiomas con los que planea usar esto.
Para obtener más información acerca de este problema reversión Unicode leyeron: http://msmvps.com/blogs/jon_skeet/archive/2009/11/02/omg-ponies-aka-humanity-epic-fail.aspx
Lo anterior no tiene en cuenta las líneas terminadas con CR y LF. – Jags
su implementación multilínea no funciona en sus casos especiales de filePointer == fileLength, la línea se mantendrá igual, por lo tanto, la línea de condición == no se activará después de eso y el código leerá todo el archivo. – ZPiDER
Usted puede cambiar fácilmente el código de abajo para imprimir la última línea.
archivo proyectado en memoria para la impresión últimos 5 líneas:
private static void printByMemoryMappedFile(File file) throws FileNotFoundException, IOException{
FileInputStream fileInputStream=new FileInputStream(file);
FileChannel channel=fileInputStream.getChannel();
ByteBuffer buffer=channel.map(FileChannel.MapMode.READ_ONLY, 0, channel.size());
buffer.position((int)channel.size());
int count=0;
StringBuilder builder=new StringBuilder();
for(long i=channel.size()-1;i>=0;i--){
char c=(char)buffer.get((int)i);
builder.append(c);
if(c=='\n'){
if(count==5)break;
count++;
builder.reverse();
System.out.println(builder.toString());
builder=null;
builder=new StringBuilder();
}
}
channel.close();
}
RandomAccessFile para imprimir últimos 5 líneas:
private static void printByRandomAcessFile(File file) throws FileNotFoundException, IOException{
RandomAccessFile randomAccessFile = new RandomAccessFile(file, "r");
int lines = 0;
StringBuilder builder = new StringBuilder();
long length = file.length();
length--;
randomAccessFile.seek(length);
for(long seek = length; seek >= 0; --seek){
randomAccessFile.seek(seek);
char c = (char)randomAccessFile.read();
builder.append(c);
if(c == '\n'){
builder = builder.reverse();
System.out.println(builder.toString());
lines++;
builder = null;
builder = new StringBuilder();
if (lines == 5){
break;
}
}
}
}
Apache Commons tiene una implementación usando RandomAccessFile.
Se llama ReversedLinesFileReader.
Creo que esta es la forma más rápida de leer el archivo en orden inverso –
parece que no lee n líneas como la respuesta aceptada. – JuanToroMarty
@JuanToroMarty Es posible recorrer el método 'readLine()'. – Stephan
Ésta es una manera de que me hizo pasar :) Espero que ayude
try(BufferedReader reader = new BufferedReader(new FileReader(reqFile))){
String line = null;
System.out.println("======================================");
line = reader.readLine(); //Read Line ONE
line = reader.readLine(); //Read Line TWO
System.out.println("first line : " + line);
//Length of one line if lines are of even length
int len = line.length();
//skip to the end - 3 lines
reader.skip((reqFile.length() - (len*3)));
//Searched to the last line for the date I was looking for.
while((line = reader.readLine()) != null){
System.out.println("FROM LINE : " + line);
String date = line.substring(0,line.indexOf(","));
System.out.println("DATE : " + date); //BAM!!!!!!!!!!!!!!
}
System.out.println(reqFile.getName() + " Read(" + reqFile.length()/(1000) + "KB)");
System.out.println("======================================");
} catch (IOException x){
x.printStackTrace();
}
- 1. ¿Cómo borrar la última línea en un archivo de texto?
- 2. Eliminar la última línea de un archivo
- 3. Leer la última línea del archivo de texto
- 4. ¿Leyó el archivo de texto en Google GWT?
- 5. shell: elimine la última línea de un gran archivo de registro de texto
- 6. Búsqueda eficiente de la última línea en un archivo de texto
- 7. ¿Justifica la última línea de un div?
- 8. ¿Cómo modifico la última línea de un archivo?
- 9. ¿Imprimir solo la última línea de un archivo?
- 10. SharpSVN leyó TODOS los nombres de archivo
- 11. C++ forma más rápida de leer solo la última línea de archivo de texto?
- 12. Lectura de un Archivo de texto hasta EOF repite última línea
- 13. Scrapy ¿leyó la lista de URL del archivo para raspar?
- 14. PHP - ¿Devolviendo la última línea en un archivo?
- 15. ¿Cómo borrar la última línea de archivo en Ruby?
- 16. Cómo leer eficientemente solo la última línea del archivo de texto
- 17. ¿Cómo eliminar rápidamente todo el texto en la línea de comandos de emacs?
- 18. Eliminación de la última línea en blanco
- 19. leyendo un archivo de texto en R línea por línea
- 20. Leyendo un archivo de texto en MATLAB línea por línea
- 21. Leer un archivo de texto línea por línea en Qt
- 22. ¿Leyó un archivo de Excel en la memoria (matriz de bytes) con ADO.NET?
- 23. FileHelpers: Cómo omitir primera y última línea de la lectura de texto de ancho fijo
- 24. SED + eliminan cadena sólo en la última línea del archivo
- 25. Anexando a la última línea del archivo CSV en Java
- 26. Extracción de la primera línea de un archivo de texto en C#
- 27. Obtener ancho de la última línea de UILabel UILabel
- 28. Comando de Unix para copiar la última línea de archivo a otro archivo
- 29. Espera en la última línea de método
- 30. C# saltarse primera línea de un archivo de texto
UTF-8 no importa - lo que necesita la última CR o de salto, que es un solo byte en ASCII y UTF -8. – MSalters
@MSalters: Buen punto. Se actualizará ... –