Ich muss eine große Textdatei von ca. 5-6 GB Zeile für Zeile mit Java lesen.
Wie kann ich das schnell machen?
Ich muss eine große Textdatei von ca. 5-6 GB Zeile für Zeile mit Java lesen.
Wie kann ich das schnell machen?
Antworten:
Ein übliches Muster ist zu verwenden
try (BufferedReader br = new BufferedReader(new FileReader(file))) {
String line;
while ((line = br.readLine()) != null) {
// process the line.
}
}
Sie können die Daten schneller lesen, wenn Sie davon ausgehen, dass keine Zeichencodierung vorhanden ist. zB ASCII-7, aber es macht keinen großen Unterschied. Es ist sehr wahrscheinlich, dass das, was Sie mit den Daten tun, viel länger dauert.
BEARBEITEN: Ein weniger verbreitetes Muster, das das Ausmaß von line
Undichtigkeiten vermeidet .
try(BufferedReader br = new BufferedReader(new FileReader(file))) {
for(String line; (line = br.readLine()) != null; ) {
// process the line.
}
// line is not visible here.
}
UPDATE: In Java 8 können Sie dies tun
try (Stream<String> stream = Files.lines(Paths.get(fileName))) {
stream.forEach(System.out::println);
}
ANMERKUNG: Sie müssen den Stream in einem Try-with-Resource- Block platzieren, um sicherzustellen, dass die # close-Methode darauf aufgerufen wird. Andernfalls wird das zugrunde liegende Dateihandle erst geschlossen, wenn GC dies viel später tut.
for(String line = br.readLine(); line != null; line = br.readLine())
übrigens, in Java 8 können Sie tun, try( Stream<String> lines = Files.lines(...) ){ for( String line : (Iterable<String>) lines::iterator ) { ... } }
was schwer zu hassen ist.
Schauen Sie sich diesen Blog an:
Die Puffergröße kann angegeben oder die Standardgröße verwendet werden. Die Standardeinstellung ist für die meisten Zwecke groß genug.
// 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
und der falsche Stream ist geschlossen. An dem Java-Lernprogramm ist nichts auszusetzen, und es ist nicht erforderlich, willkürlichen Internet-Müll von Drittanbietern wie diesen zu zitieren.
Sobald Java 8 veröffentlicht ist (März 2014), können Sie Streams verwenden:
try (Stream<String> lines = Files.lines(Paths.get(filename), Charset.defaultCharset())) {
lines.forEachOrdered(line -> process(line));
}
Drucken aller Zeilen in der Datei:
try (Stream<String> lines = Files.lines(file, Charset.defaultCharset())) {
lines.forEachOrdered(System.out::println);
}
StandardCharsets.UTF_8
, verwenden Sie Stream<String>
für die Prägnanz und vermeiden Sie die Verwendung forEach()
und insbesondere, forEachOrdered()
wenn es keinen Grund gibt.
forEach(this::process)
, aber es wird hässlich, wenn Sie Codeblöcke als Lambdas darin schreiben forEach()
.
forEachOrdered
, um in der richtigen Reihenfolge auszuführen. Beachten Sie, dass Sie den Stream in diesem Fall nicht parallelisieren können, obwohl ich festgestellt habe, dass die Parallelisierung nur aktiviert wird, wenn die Datei Tausende von Zeilen enthält.
Hier ist ein Beispiel mit vollständiger Fehlerbehandlung und unterstützender Zeichensatzspezifikation für Pre-Java 7. Mit Java 7 können Sie die Try-with-Resources-Syntax verwenden, wodurch der Code sauberer wird.
Wenn Sie nur den Standardzeichensatz möchten, können Sie den InputStream überspringen und FileReader verwenden.
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 */ } }
}
Hier ist die Groovy-Version mit vollständiger Fehlerbehandlung:
File f = new File("textfile.txt");
f.withReader("UTF-8") { br ->
br.eachLine { line ->
println line;
}
}
ByteArrayInputStream
von einem String gespeistes Literal mit dem Lesen einer großen Textdatei zu tun?
In Java 8 können Sie Folgendes tun:
try (Stream<String> lines = Files.lines (file, StandardCharsets.UTF_8))
{
for (String line : (Iterable<String>) lines::iterator)
{
;
}
}
Einige Hinweise: Der von Files.lines
(im Gegensatz zu den meisten Streams) zurückgegebene Stream muss geschlossen werden. Aus den hier genannten Gründen vermeide ich die Verwendung forEach()
. Der seltsame Code (Iterable<String>) lines::iterator
wandelt einen Stream in ein Iterable um.
Iterable
dieser Code nicht implementiert wird, ist er definitiv hässlich, obwohl er nützlich ist. Es braucht eine Besetzung (dh (Iterable<String>)
), um zu arbeiten.
for(String line : (Iterable<String>) lines.skip(1)::iterator)
Stream
, scheint es viel einfacher zu sein , Konstrukteure Files.newBufferedReader
anstelle von Files.lines
und wiederholt aufzurufen, readLine()
bis sie null
anstelle von Konstrukten wie verwendet (Iterable<String>) lines::iterator
werden…
Sie können den gesamten Text mit dem Scanner scannen und den Text zeilenweise durchgehen. Natürlich sollten Sie Folgendes importieren:
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
}
}
Der Scanner scannt grundsätzlich den gesamten Text. Die while-Schleife wird verwendet, um den gesamten Text zu durchlaufen.
Die .hasNextLine()
Funktion ist ein Boolescher Wert, der true zurückgibt, wenn der Text noch mehr Zeilen enthält. Die .nextLine()
Funktion gibt Ihnen eine ganze Zeile als Zeichenfolge, die Sie dann nach Ihren Wünschen verwenden können. Versuchen Sie System.out.println(line)
, den Text zu drucken.
Randnotiz: .txt ist der Dateityptext.
BufferedReader.readLine()
, und er fragte nach der leistungsstärksten Methode.
Mit FileReader können Sie die Codierung nicht angeben. Verwenden Sie sie InputStreamReader
stattdessen, wenn Sie sie angeben müssen:
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();
}
Wenn Sie diese Datei aus Windows importiert haben, verfügt sie möglicherweise über eine ANSI-Codierung (Cp1252), daher müssen Sie die Codierung angeben.
Ich habe 10 verschiedene Möglichkeiten zum Lesen einer Datei in Java dokumentiert und getestet und sie dann gegeneinander ausgeführt, indem ich sie in Testdateien von 1 KB bis 1 GB einlesen ließ. Hier sind die schnellsten 3 Methoden zum Lesen von Dateien zum Lesen einer 1-GB-Testdatei.
Beachten Sie, dass ich beim Ausführen der Leistungstests nichts an die Konsole ausgegeben habe, da dies den Test wirklich verlangsamen würde. Ich wollte nur die rohe Lesegeschwindigkeit testen.
1) java.nio.file.Files.readAllBytes ()
Getestet in Java 7, 8, 9. Dies war insgesamt die schnellste Methode. Das Lesen einer 1-GB-Datei dauerte durchweg knapp 1 Sekunde.
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 ()
Dies wurde erfolgreich in Java 8 und 9 getestet, funktioniert jedoch in Java 7 nicht, da Lambda-Ausdrücke nicht unterstützt werden. Das Einlesen einer 1-GB-Datei dauerte ungefähr 3,5 Sekunden, womit sie beim Lesen größerer Dateien an zweiter Stelle stand.
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
Getestet für Java 7, 8, 9. Das Einlesen einer 1-GB-Testdatei dauerte ca. 4,5 Sekunden.
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);
}
}
}
Die vollständige Rangliste für alle 10 Methoden zum Lesen von Dateien finden Sie hier .
System.out.print/println()
hier meistens ; Sie gehen auch davon aus, dass die Datei in Ihren ersten beiden Fällen in den Speicher passt.
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
, um die aktivierte Ausnahme inCharset.forName("UTF-8")
In Java 8 gibt es auch eine Alternative zur Verwendung Files.lines()
. Wenn Ihre Eingabequelle keine Datei ist, sondern etwas Abstrakteres wie a Reader
oder an InputStream
, können Sie die Zeilen über die Methode s streamen .BufferedReader
lines()
Zum Beispiel:
try (BufferedReader reader = new BufferedReader(...)) {
reader.lines().forEach(line -> processLine(line));
}
ruft processLine()
für jede Eingabezeile auf, die von der gelesen wird BufferedReader
.
Zum Lesen einer Datei mit 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();
}
}
}
Sie können die Scannerklasse verwenden
Scanner sc=new Scanner(file);
sc.nextLine();
Scanner
ist in Ordnung, aber diese Antwort enthält nicht den vollständigen Code, um sie ordnungsgemäß zu verwenden.
BufferedReader.readLine()
sicherlich um ein Vielfaches schneller ist. Wenn Sie anders denken, geben Sie bitte Ihre Gründe an.
Sie müssen die readLine()
Methode in verwenden class BufferedReader
. Erstellen Sie ein neues Objekt aus dieser Klasse, führen Sie diese Methode für ihn aus und speichern Sie es in einer Zeichenfolge.
Der klare Weg, um dies zu erreichen,
Zum Beispiel:
Wenn Sie dataFile.txt
in Ihrem aktuellen Verzeichnis haben
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");
}
Für mich geht das. Hoffe, es wird dir auch helfen.
Sie können Streams verwenden, um dies genauer zu tun:
Files.lines(Paths.get("input.txt")).forEach(s -> stringBuffer.append(s);
Normalerweise mache ich die Leseroutine unkompliziert:
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) {
}
}
}
Sie können diesen Code verwenden:
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();
}
}
}
Durch die Verwendung des Pakets org.apache.commons.io wurde eine höhere Leistung erzielt , insbesondere bei Legacy-Code, der Java 6 und niedriger verwendet.
Java 7 verfügt über eine bessere API mit weniger Ausnahmebehandlung und nützlicheren Methoden:
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>
Sie können auch Apache Commons IO verwenden :
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)
ist eine veraltete Methode. Darüber hinaus ruft die Methode auf IOUtils.readLines
, die einen BufferedReader und eine ArrayList verwendet. Dies ist keine zeilenweise Methode und sicherlich keine, die zum Lesen mehrerer GB praktisch wäre.