Ho bisogno di leggere un grande file di testo di circa 5-6 GB riga per riga usando Java.
Come posso farlo rapidamente?
Ho bisogno di leggere un grande file di testo di circa 5-6 GB riga per riga usando Java.
Come posso farlo rapidamente?
Risposte:
Un modello comune è quello di utilizzare
try (BufferedReader br = new BufferedReader(new FileReader(file))) {
String line;
while ((line = br.readLine()) != null) {
// process the line.
}
}
Puoi leggere i dati più velocemente se pensi che non ci sia la codifica dei caratteri. ad esempio ASCII-7 ma non farà molta differenza. È molto probabile che ciò che fai con i dati richiederà molto più tempo.
EDIT: un modello meno comune da utilizzare che evita la portata delle line
perdite.
try(BufferedReader br = new BufferedReader(new FileReader(file))) {
for(String line; (line = br.readLine()) != null; ) {
// process the line.
}
// line is not visible here.
}
AGGIORNAMENTO: In Java 8 puoi farlo
try (Stream<String> stream = Files.lines(Paths.get(fileName))) {
stream.forEach(System.out::println);
}
NOTA: è necessario posizionare lo Stream in un blocco try-with-resource per assicurarsi che venga richiamato il metodo #close, altrimenti l'handle del file sottostante non verrà mai chiuso fino a quando GC non lo farà molto più tardi.
for(String line = br.readLine(); line != null; line = br.readLine())
Btw, in Java 8 puoi fare try( Stream<String> lines = Files.lines(...) ){ for( String line : (Iterable<String>) lines::iterator ) { ... } }
che è difficile non odiare.
Guarda questo blog:
È possibile specificare la dimensione del buffer o utilizzare la dimensione predefinita. L'impostazione predefinita è abbastanza grande per la maggior parte degli scopi.
// 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
e lo stream sbagliato è chiuso. Nulla di sbagliato con il tutorial Java, e non c'è bisogno di citare rifiuti Internet arbitrari di terze parti come questo.
Una volta uscito Java 8 (marzo 2014) sarai in grado di usare i flussi:
try (Stream<String> lines = Files.lines(Paths.get(filename), Charset.defaultCharset())) {
lines.forEachOrdered(line -> process(line));
}
Stampa di tutte le righe nel file:
try (Stream<String> lines = Files.lines(file, Charset.defaultCharset())) {
lines.forEachOrdered(System.out::println);
}
StandardCharsets.UTF_8
, usa Stream<String>
per concisione ed evita di usare forEach()
e soprattutto a forEachOrdered()
meno che non ci sia una ragione.
forEach(this::process)
, ma diventa brutto se scrivi blocchi di codice come lambdas all'interno forEach()
.
forEachOrdered
per eseguire in ordine. Tieni presente che in quel caso non sarai in grado di parallelizzare lo stream, anche se ho scoperto che la parallelizzazione non si attiva a meno che il file non contenga migliaia di righe.
Ecco un esempio con la gestione completa degli errori e il supporto delle specifiche del set di caratteri per pre-Java 7. Con Java 7 è possibile utilizzare la sintassi di prova con risorse, che rende il codice più pulito.
Se si desidera solo il set di caratteri predefinito, è possibile saltare InputStream e utilizzare 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 */ } }
}
Ecco la versione Groovy, con gestione completa degli errori:
File f = new File("textfile.txt");
f.withReader("UTF-8") { br ->
br.eachLine { line ->
println line;
}
}
ByteArrayInputStream
feed con una stringa letterale con la lettura di un file di testo di grandi dimensioni?
In Java 8, puoi fare:
try (Stream<String> lines = Files.lines (file, StandardCharsets.UTF_8))
{
for (String line : (Iterable<String>) lines::iterator)
{
;
}
}
Alcune note: lo stream restituito da Files.lines
(diversamente dalla maggior parte degli stream) deve essere chiuso. Per i motivi menzionati qui evito di usare forEach()
. Lo strano codice (Iterable<String>) lines::iterator
lancia uno Stream su un Iterable.
Iterable
questo codice è definitivamente brutto sebbene utile. Ha bisogno di un cast (cioè (Iterable<String>)
) per funzionare.
for(String line : (Iterable<String>) lines.skip(1)::iterator)
Stream
funzionalità, usare Files.newBufferedReader
invece di Files.lines
e chiamare ripetutamente readLine()
fino a quando null
invece di usare costrutti come (Iterable<String>) lines::iterator
sembra essere molto più semplice ...
Quello che puoi fare è scansionare l'intero testo usando Scanner e scorrere il testo riga per riga. Ovviamente dovresti importare quanto segue:
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
}
}
Lo scanner fondamentalmente scansiona tutto il testo. Il ciclo while viene utilizzato per attraversare l'intero testo.
La .hasNextLine()
funzione è un valore booleano che restituisce true se ci sono ancora più righe nel testo. La .nextLine()
funzione ti fornisce un'intera riga come stringa che puoi quindi usare nel modo desiderato. Prova System.out.println(line)
a stampare il testo.
Nota a margine: .txt è il testo del tipo di file.
BufferedReader.readLine()
, e ha chiesto il metodo più performante.
FileReader non ti consente di specificare la codifica, utilizzare InputStreamReader
invece se è necessario specificarlo:
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();
}
Se hai importato questo file da Windows, potrebbe avere la codifica ANSI (Cp1252), quindi devi specificare la codifica.
Ho documentato e testato 10 modi diversi per leggere un file in Java e poi li ho eseguiti l'uno contro l'altro facendoli leggere in file di test da 1KB a 1GB. Ecco i 3 metodi di lettura dei file più veloci per la lettura di un file di test da 1 GB.
Si noti che durante l'esecuzione dei test delle prestazioni non ho prodotto nulla sulla console poiché ciò rallenterebbe davvero il test. Volevo solo testare la velocità di lettura pura.
1) java.nio.file.Files.readAllBytes ()
Testato in Java 7, 8, 9. Questo è stato nel complesso il metodo più veloce. La lettura di un file da 1 GB era costantemente poco meno di 1 secondo.
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 ()
Questo è stato testato con successo in Java 8 e 9 ma non funzionerà in Java 7 a causa della mancanza di supporto per le espressioni lambda. Ci sono voluti circa 3,5 secondi per leggere in un file da 1 GB che lo metteva al secondo posto per quanto riguarda la lettura di file più grandi.
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
Testato per funzionare in Java 7, 8, 9. Questa lettura ha richiesto circa 4,5 secondi in un file di test da 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);
}
}
}
Puoi trovare le classifiche complete per tutti i 10 metodi di lettura dei file qui .
System.out.print/println()
qui; stai anche assumendo che il file si adatti alla memoria nei tuoi primi due casi.
In 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
per evitare l'eccezione verificata inCharset.forName("UTF-8")
In Java 8, esiste anche un'alternativa all'utilizzo Files.lines()
. Se la tua sorgente di input non è un file ma qualcosa di più astratto come un Reader
o un InputStream
, puoi eseguire lo streaming delle linee tramite il metodo BufferedReader
s lines()
.
Per esempio:
try (BufferedReader reader = new BufferedReader(...)) {
reader.lines().forEach(line -> processLine(line));
}
chiamerà processLine()
per ogni linea di input letta da BufferedReader
.
Per leggere un file 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();
}
}
}
È possibile utilizzare la classe Scanner
Scanner sc=new Scanner(file);
sc.nextLine();
Scanner
va bene, ma questa risposta non include il codice completo per usarlo correttamente.
BufferedReader.readLine()
sia certamente più volte più veloce. Se la pensi diversamente, specifica i motivi.
Devi usare il readLine()
metodo in class BufferedReader
. Crea un nuovo oggetto da quella classe e utilizza questo metodo su di lui e salvalo in una stringa.
Il modo chiaro per raggiungere questo obiettivo,
Per esempio:
Se hai dataFile.txt
sulla tua directory corrente
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");
}
Per me funziona. Spero che possa aiutarti anche tu.
Puoi usare gli stream per farlo in modo più preciso:
Files.lines(Paths.get("input.txt")).forEach(s -> stringBuffer.append(s);
Di solito faccio la routine di lettura semplice:
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) {
}
}
}
Puoi usare questo codice:
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();
}
}
}
Utilizzando il pacchetto org.apache.commons.io , ha fornito maggiori prestazioni, soprattutto nel codice legacy che utilizza Java 6 e versioni precedenti.
Java 7 ha un'API migliore con meno gestione delle eccezioni e metodi più utili:
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>
Puoi anche usare 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)
è un metodo deprecato. Inoltre, viene invocato il metodo IOUtils.readLines
, che utilizza BufferedReader e ArrayList. Questo non è un metodo riga per riga, e certamente non uno che sarebbe pratico per leggere diversi GB.