Necesito leer un archivo de texto grande de alrededor de 5-6 GB línea por línea usando Java.
¿Cómo puedo hacer esto rápidamente?
java
performance
file-io
io
garbage-collection
manoj singh
fuente
fuente
Respuestas:
Un patrón común es usar
Puede leer los datos más rápido si supone que no hay codificación de caracteres. ej. ASCII-7 pero no hará mucha diferencia. Es muy probable que lo que haga con los datos tarde mucho más.
EDITAR: un patrón menos común para usar que evita el alcance de las
line
fugas.ACTUALIZACIÓN: En Java 8 puedes hacer
NOTA: Debe colocar la secuencia en un bloque de prueba con recursos para asegurarse de que se invoque el método #close, de lo contrario, el identificador de archivo subyacente nunca se cerrará hasta que GC lo haga mucho más tarde.
fuente
for(String line = br.readLine(); line != null; line = br.readLine())
, por cierto, en Java 8 puedes hacer lotry( Stream<String> lines = Files.lines(...) ){ for( String line : (Iterable<String>) lines::iterator ) { ... } }
que es difícil de no odiar.Mira este blog:
fuente
DataInputStream
, y se cierra la secuencia incorrecta. No hay nada malo con el Tutorial de Java, y no es necesario citar basura arbitraria de Internet de terceros como esta.Una vez que Java 8 esté fuera (marzo de 2014), podrá usar transmisiones:
Imprimir todas las líneas en el archivo:
fuente
StandardCharsets.UTF_8
, useStream<String>
por concisión, y evite usarforEach()
y especialmente aforEachOrdered()
menos que haya una razón.forEach(this::process)
, pero se pone feo si escribe bloques de código como lambdas en su interiorforEach()
.forEachOrdered
para ejecutar en orden. Tenga en cuenta que no podrá paralelizar la transmisión en ese caso, aunque descubrí que la paralelización no se activa a menos que el archivo tenga miles de líneas.Aquí hay una muestra con manejo completo de errores y soporte de especificación de juego de caracteres para pre-Java 7. Con Java 7 puede usar la sintaxis de prueba con recursos, lo que hace que el código sea más limpio.
Si solo desea el conjunto de caracteres predeterminado, puede omitir InputStream y usar FileReader.
Aquí está la versión Groovy, con manejo completo de errores:
fuente
ByteArrayInputStream
literal alimentado por una cadena con la lectura de un archivo de texto grande?En Java 8, podrías hacer:
Algunas notas: La secuencia devuelta por
Files.lines
(a diferencia de la mayoría de las secuencias) debe cerrarse. Por las razones mencionadas aquí , evito usarforEach()
. El extraño código(Iterable<String>) lines::iterator
arroja un Stream a un Iterable.fuente
Iterable
este código es definitivamente feo aunque útil. Necesita un yeso (es decir(Iterable<String>)
) para funcionar.for(String line : (Iterable<String>) lines.skip(1)::iterator)
Stream
características, usar enFiles.newBufferedReader
lugar deFiles.lines
y llamar repetidamentereadLine()
hasta que ennull
lugar de usar construcciones como(Iterable<String>) lines::iterator
parece ser mucho más simple ...Lo que puede hacer es escanear todo el texto con Scanner y recorrer el texto línea por línea. Por supuesto, debe importar lo siguiente:
El escáner básicamente escanea todo el texto. El bucle while se usa para recorrer todo el texto.
La
.hasNextLine()
función es un valor booleano que devuelve verdadero si aún hay más líneas en el texto. La.nextLine()
función le proporciona una línea completa como una Cadena que luego puede usar de la manera que desee. IntentaSystem.out.println(line)
imprimir el texto.Nota al margen: .txt es el texto del tipo de archivo.
fuente
BufferedReader.readLine()
, y pidió el método con mejor rendimiento.FileReader no le permitirá especificar la codificación, use
InputStreamReader
en su lugar si necesita especificarla:Si importó este archivo desde Windows, podría tener codificación ANSI (Cp1252), por lo que debe especificar la codificación.
fuente
Documenté y probé 10 formas diferentes de leer un archivo en Java y luego las comparé entre sí al hacer que leyeran en archivos de prueba de 1 KB a 1 GB. Estos son los métodos de lectura de 3 archivos más rápidos para leer un archivo de prueba de 1 GB.
Tenga en cuenta que cuando ejecuté las pruebas de rendimiento, no envié nada a la consola, ya que eso realmente ralentizaría la prueba. Solo quería probar la velocidad de lectura en bruto.
1) java.nio.file.Files.readAllBytes ()
Probado en Java 7, 8, 9. Este fue en general el método más rápido. Leer un archivo de 1GB fue consistentemente un poco menos de 1 segundo.
2) java.nio.file.Files.lines ()
Esto se probó con éxito en Java 8 y 9, pero no funcionará en Java 7 debido a la falta de soporte para expresiones lambda. Le tomó alrededor de 3.5 segundos leer un archivo de 1GB que lo colocó en segundo lugar en cuanto a leer archivos más grandes.
3) BufferedReader
Probado para funcionar en Java 7, 8, 9. Esto tardó aproximadamente 4,5 segundos en leer en un archivo de prueba de 1 GB.
Puede encontrar la clasificación completa de los 10 métodos de lectura de archivos aquí .
fuente
System.out.print/println()
aquí; también está asumiendo que el archivo encajará en la memoria en sus dos primeros casos.En Java 7:
fuente
StandardCharsets.UTF_8
para evitar la excepción marcada enCharset.forName("UTF-8")
En Java 8, también hay una alternativa al uso
Files.lines()
. Si su fuente de entrada no es un archivo, sino algo más abstracto como aReader
o anInputStream
, puede transmitir las líneas a través del métodoBufferedReader
slines()
.Por ejemplo:
llamará
processLine()
a cada línea de entrada leída porBufferedReader
.fuente
Para leer un archivo con Java 8
fuente
Puedes usar la clase Scanner
fuente
Scanner
está bien, pero esta respuesta no incluye el código completo para usarlo correctamente.BufferedReader.readLine()
ciertamente es varias veces más rápido. Si piensa lo contrario, indique sus razones.Necesitas usar el
readLine()
método enclass BufferedReader
. Cree un nuevo objeto de esa clase y opere este método en él y guárdelo en una cadena.BufferReader Javadoc
fuente
La forma clara de lograr esto,
Por ejemplo:
Si tienes
dataFile.txt
en tu directorio actualLa salida como a continuación,
fuente
Java 9:
fuente
System.getProperty("os.name").equals("Linux")
==
!Esto funciona para mi. Espero que te ayude también.
fuente
Puede usar transmisiones para hacerlo con mayor precisión:
fuente
Usualmente hago la rutina de lectura directa:
fuente
Puedes usar este código:
fuente
Al usar el paquete org.apache.commons.io , proporcionó más rendimiento, especialmente en el código heredado que usa Java 6 y versiones posteriores.
Java 7 tiene una mejor API con menos manejo de excepciones y métodos más útiles:
Maven
fuente
También puede usar Apache Commons IO :
fuente
FileUtils.readLines(file)
Es un método obsoleto. Además, el método invocaIOUtils.readLines
, que utiliza un BufferedReader y ArrayList. Este no es un método línea por línea, y ciertamente no es uno que sea práctico para leer varios GB.