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?
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?
Respuestas:
Un patrón común es usar
try (BufferedReader br = new BufferedReader(new FileReader(file))) {
String line;
while ((line = br.readLine()) != null) {
// process the line.
}
}
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.
try(BufferedReader br = new BufferedReader(new FileReader(file))) {
for(String line; (line = br.readLine()) != null; ) {
// process the line.
}
// line is not visible here.
}
ACTUALIZACIÓN: En Java 8 puedes hacer
try (Stream<String> stream = Files.lines(Paths.get(fileName))) {
stream.forEach(System.out::println);
}
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.
for(String line = br.readLine(); line != null; line = br.readLine())
, por cierto, en Java 8 puedes hacer lo try( Stream<String> lines = Files.lines(...) ){ for( String line : (Iterable<String>) lines::iterator ) { ... } }
que es difícil de no odiar.
Mira este blog:
Se puede especificar el tamaño del búfer o se puede usar el tamaño predeterminado. El valor predeterminado es lo suficientemente grande para la mayoría de los propósitos.
// Open the file
FileInputStream fstream = new FileInputStream("textfile.txt");
BufferedReader br = new BufferedReader(new InputStreamReader(fstream));
String strLine;
//Read File Line By Line
while ((strLine = br.readLine()) != null) {
// Print the content on the console
System.out.println (strLine);
}
//Close the input stream
fstream.close();
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:
try (Stream<String> lines = Files.lines(Paths.get(filename), Charset.defaultCharset())) {
lines.forEachOrdered(line -> process(line));
}
Imprimir todas las líneas en el archivo:
try (Stream<String> lines = Files.lines(file, Charset.defaultCharset())) {
lines.forEachOrdered(System.out::println);
}
StandardCharsets.UTF_8
, use Stream<String>
por concisión, y evite usar forEach()
y especialmente a forEachOrdered()
menos que haya una razón.
forEach(this::process)
, pero se pone feo si escribe bloques de código como lambdas en su interior forEach()
.
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.
InputStream ins = null; // raw byte-stream
Reader r = null; // cooked reader
BufferedReader br = null; // buffered for readLine()
try {
String s;
ins = new FileInputStream("textfile.txt");
r = new InputStreamReader(ins, "UTF-8"); // leave charset out for default
br = new BufferedReader(r);
while ((s = br.readLine()) != null) {
System.out.println(s);
}
}
catch (Exception e)
{
System.err.println(e.getMessage()); // handle exception
}
finally {
if (br != null) { try { br.close(); } catch(Throwable t) { /* ensure close happens */ } }
if (r != null) { try { r.close(); } catch(Throwable t) { /* ensure close happens */ } }
if (ins != null) { try { ins.close(); } catch(Throwable t) { /* ensure close happens */ } }
}
Aquí está la versión Groovy, con manejo completo de errores:
File f = new File("textfile.txt");
f.withReader("UTF-8") { br ->
br.eachLine { line ->
println line;
}
}
ByteArrayInputStream
literal alimentado por una cadena con la lectura de un archivo de texto grande?
En Java 8, podrías hacer:
try (Stream<String> lines = Files.lines (file, StandardCharsets.UTF_8))
{
for (String line : (Iterable<String>) lines::iterator)
{
;
}
}
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 usar forEach()
. El extraño código (Iterable<String>) lines::iterator
arroja un Stream a un Iterable.
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 en Files.newBufferedReader
lugar de Files.lines
y llamar repetidamente readLine()
hasta que en null
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:
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;
public static void readText throws FileNotFoundException {
Scanner scan = new Scanner(new File("samplefilename.txt"));
while(scan.hasNextLine()){
String line = scan.nextLine();
//Here you can manipulate the string the way you want
}
}
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. Intenta System.out.println(line)
imprimir el texto.
Nota al margen: .txt es el texto del tipo de archivo.
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:
try {
BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(filePath), "Cp1252"));
String line;
while ((line = br.readLine()) != null) {
// process the line.
}
br.close();
} catch (IOException e) {
e.printStackTrace();
}
Si importó este archivo desde Windows, podría tener codificación ANSI (Cp1252), por lo que debe especificar la codificación.
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.
import java.io..File;
import java.io.IOException;
import java.nio.file.Files;
public class ReadFile_Files_ReadAllBytes {
public static void main(String [] pArgs) throws IOException {
String fileName = "c:\\temp\\sample-1GB.txt";
File file = new File(fileName);
byte [] fileBytes = Files.readAllBytes(file.toPath());
char singleChar;
for(byte b : fileBytes) {
singleChar = (char) b;
System.out.print(singleChar);
}
}
}
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.
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.util.stream.Stream;
public class ReadFile_Files_Lines {
public static void main(String[] pArgs) throws IOException {
String fileName = "c:\\temp\\sample-1GB.txt";
File file = new File(fileName);
try (Stream linesStream = Files.lines(file.toPath())) {
linesStream.forEach(line -> {
System.out.println(line);
});
}
}
}
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.
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
public class ReadFile_BufferedReader_ReadLine {
public static void main(String [] args) throws IOException {
String fileName = "c:\\temp\\sample-1GB.txt";
FileReader fileReader = new FileReader(fileName);
try (BufferedReader bufferedReader = new BufferedReader(fileReader)) {
String line;
while((line = bufferedReader.readLine()) != null) {
System.out.println(line);
}
}
}
Puede encontrar la clasificación completa de los 10 métodos de lectura de archivos aquí .
System.out.print/println()
aquí; también está asumiendo que el archivo encajará en la memoria en sus dos primeros casos.
En Java 7:
String folderPath = "C:/folderOfMyFile";
Path path = Paths.get(folderPath, "myFileName.csv"); //or any text file eg.: txt, bat, etc
Charset charset = Charset.forName("UTF-8");
try (BufferedReader reader = Files.newBufferedReader(path , charset)) {
while ((line = reader.readLine()) != null ) {
//separate all csv fields into string array
String[] lineVariables = line.split(",");
}
} catch (IOException e) {
System.err.println(e);
}
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 a Reader
o an InputStream
, puede transmitir las líneas a través del método BufferedReader
s lines()
.
Por ejemplo:
try (BufferedReader reader = new BufferedReader(...)) {
reader.lines().forEach(line -> processLine(line));
}
llamará processLine()
a cada línea de entrada leída por BufferedReader
.
Para leer un archivo con Java 8
package com.java.java8;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.stream.Stream;
/**
* The Class ReadLargeFile.
*
* @author Ankit Sood Apr 20, 2017
*/
public class ReadLargeFile {
/**
* The main method.
*
* @param args
* the arguments
*/
public static void main(String[] args) {
try {
Stream<String> stream = Files.lines(Paths.get("C:\\Users\\System\\Desktop\\demoData.txt"));
stream.forEach(System.out::println);
}
catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Puedes usar la clase Scanner
Scanner sc=new Scanner(file);
sc.nextLine();
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 en class BufferedReader
. Cree un nuevo objeto de esa clase y opere este método en él y guárdelo en una cadena.
La forma clara de lograr esto,
Por ejemplo:
Si tienes dataFile.txt
en tu directorio actual
import java.io.*;
import java.util.Scanner;
import java.io.FileNotFoundException;
public class readByLine
{
public readByLine() throws FileNotFoundException
{
Scanner linReader = new Scanner(new File("dataFile.txt"));
while (linReader.hasNext())
{
String line = linReader.nextLine();
System.out.println(line);
}
linReader.close();
}
public static void main(String args[]) throws FileNotFoundException
{
new readByLine();
}
}
try (Stream<String> stream = Files.lines(Paths.get(fileName))) {
stream.forEach(System.out::println);
}
System.getProperty("os.name").equals("Linux")
==
!
BufferedReader br;
FileInputStream fin;
try {
fin = new FileInputStream(fileName);
br = new BufferedReader(new InputStreamReader(fin));
/*Path pathToFile = Paths.get(fileName);
br = Files.newBufferedReader(pathToFile,StandardCharsets.US_ASCII);*/
String line = br.readLine();
while (line != null) {
String[] attributes = line.split(",");
Movie movie = createMovie(attributes);
movies.add(movie);
line = br.readLine();
}
fin.close();
br.close();
} catch (FileNotFoundException e) {
System.out.println("Your Message");
} catch (IOException e) {
System.out.println("Your Message");
}
Esto funciona para mi. Espero que te ayude también.
Puede usar transmisiones para hacerlo con mayor precisión:
Files.lines(Paths.get("input.txt")).forEach(s -> stringBuffer.append(s);
Usualmente hago la rutina de lectura directa:
void readResource(InputStream source) throws IOException {
BufferedReader stream = null;
try {
stream = new BufferedReader(new InputStreamReader(source));
while (true) {
String line = stream.readLine();
if(line == null) {
break;
}
//process line
System.out.println(line)
}
} finally {
closeQuiet(stream);
}
}
static void closeQuiet(Closeable closeable) {
if (closeable != null) {
try {
closeable.close();
} catch (IOException ignore) {
}
}
}
Puedes usar este código:
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
public class ReadTextFile {
public static void main(String[] args) throws IOException {
try {
File f = new File("src/com/data.txt");
BufferedReader b = new BufferedReader(new FileReader(f));
String readLine = "";
System.out.println("Reading file using Buffered Reader");
while ((readLine = b.readLine()) != null) {
System.out.println(readLine);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
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:
LineIterator lineIterator = null;
try {
lineIterator = FileUtils.lineIterator(new File("/home/username/m.log"), "windows-1256"); // The second parameter is optionnal
while (lineIterator.hasNext()) {
String currentLine = lineIterator.next();
// Some operation
}
}
finally {
LineIterator.closeQuietly(lineIterator);
}
<!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
También puede usar Apache Commons IO :
File file = new File("/home/user/file.txt");
try {
List<String> lines = FileUtils.readLines(file);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
FileUtils.readLines(file)
Es un método obsoleto. Además, el método invoca IOUtils.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.