Saya perlu membaca file teks besar sekitar 5-6 GB baris demi baris menggunakan Java.
Bagaimana saya bisa melakukan ini dengan cepat?
Saya perlu membaca file teks besar sekitar 5-6 GB baris demi baris menggunakan Java.
Bagaimana saya bisa melakukan ini dengan cepat?
Jawaban:
Pola yang umum digunakan
try (BufferedReader br = new BufferedReader(new FileReader(file))) {
String line;
while ((line = br.readLine()) != null) {
// process the line.
}
}
Anda dapat membaca data lebih cepat jika Anda menganggap tidak ada pengkodean karakter. misalnya ASCII-7 tetapi tidak akan membuat banyak perbedaan. Sangat mungkin bahwa apa yang Anda lakukan dengan data akan memakan waktu lebih lama.
EDIT: Pola yang kurang umum untuk digunakan yang menghindari ruang lingkup line
kebocoran.
try(BufferedReader br = new BufferedReader(new FileReader(file))) {
for(String line; (line = br.readLine()) != null; ) {
// process the line.
}
// line is not visible here.
}
UPDATE: Di Java 8 Anda bisa melakukannya
try (Stream<String> stream = Files.lines(Paths.get(fileName))) {
stream.forEach(System.out::println);
}
CATATAN: Anda harus menempatkan Stream di blok coba-dengan-sumber daya untuk memastikan metode #close dipanggil, jika tidak, pegangan file yang mendasarinya tidak pernah ditutup sampai GC melakukannya nanti.
for(String line = br.readLine(); line != null; line = br.readLine())
Btw, di Jawa 8 Anda bisa melakukan try( Stream<String> lines = Files.lines(...) ){ for( String line : (Iterable<String>) lines::iterator ) { ... } }
yang sulit untuk tidak membenci.
Lihatlah blog ini:
Ukuran buffer dapat ditentukan, atau ukuran standar dapat digunakan. Standarnya cukup besar untuk sebagian besar keperluan.
// 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
, dan aliran yang salah ditutup. Tidak ada yang salah dengan Tutorial Java, dan tidak perlu mengutip sampah Internet pihak ketiga yang sewenang-wenang seperti ini.
Setelah Java 8 keluar (Maret 2014) Anda akan dapat menggunakan stream:
try (Stream<String> lines = Files.lines(Paths.get(filename), Charset.defaultCharset())) {
lines.forEachOrdered(line -> process(line));
}
Mencetak semua baris dalam file:
try (Stream<String> lines = Files.lines(file, Charset.defaultCharset())) {
lines.forEachOrdered(System.out::println);
}
StandardCharsets.UTF_8
, gunakan Stream<String>
untuk keringkasan, dan hindari menggunakan forEach()
dan terutama forEachOrdered()
kecuali ada alasannya.
forEach(this::process)
, tetapi akan jelek jika Anda menulis blok kode sebagai lambdas di dalamnya forEach()
.
forEachOrdered
menjalankan perintah. Perlu diketahui bahwa Anda tidak akan dapat memparalelkan aliran dalam kasus itu, meskipun saya telah menemukan bahwa paralelisasi tidak menyala kecuali file tersebut memiliki ribuan baris.
Berikut adalah contoh dengan penanganan kesalahan penuh dan spesifikasi charset pendukung untuk pra-Java 7. Dengan Java 7 Anda dapat menggunakan sintaks coba-dengan-sumber daya, yang membuat kode lebih bersih.
Jika Anda hanya ingin charset default, Anda dapat melewati InputStream dan menggunakan 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 */ } }
}
Ini adalah versi Groovy, dengan penanganan kesalahan penuh:
File f = new File("textfile.txt");
f.withReader("UTF-8") { br ->
br.eachLine { line ->
println line;
}
}
ByteArrayInputStream
dengan string literal hubungannya dengan membaca file teks besar?
Di Java 8, Anda bisa melakukan:
try (Stream<String> lines = Files.lines (file, StandardCharsets.UTF_8))
{
for (String line : (Iterable<String>) lines::iterator)
{
;
}
}
Beberapa catatan: Aliran dikembalikan oleh Files.lines
(tidak seperti kebanyakan aliran) perlu ditutup. Untuk alasan yang disebutkan di sini saya menghindari penggunaan forEach()
. Kode aneh (Iterable<String>) lines::iterator
melemparkan Stream ke Iterable.
Iterable
kode ini secara definitif jelek meskipun bermanfaat. Perlu pemain (yaitu (Iterable<String>)
) untuk bekerja.
for(String line : (Iterable<String>) lines.skip(1)::iterator)
Stream
fitur, menggunakan Files.newBufferedReader
alih-alih Files.lines
dan berulang kali menelepon readLine()
hingga null
alih-alih menggunakan konstruksi seperti (Iterable<String>) lines::iterator
tampaknya jauh lebih sederhana ...
Yang dapat Anda lakukan adalah memindai seluruh teks menggunakan Pemindai dan menelusuri teks baris demi baris. Tentu saja Anda harus mengimpor yang berikut ini:
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
}
}
Pemindai pada dasarnya memindai semua teks. Loop sementara digunakan untuk menelusuri seluruh teks.
The .hasNextLine()
fungsi adalah boolean yang mengembalikan true jika masih ada lebih banyak garis dalam teks. The .nextLine()
Fungsi memberikan seluruh baris sebagai String yang kemudian dapat menggunakan cara yang Anda inginkan. Coba System.out.println(line)
cetak teksnya.
Catatan Sisi: .txt adalah teks jenis file.
BufferedReader.readLine()
, dan dia meminta metode berkinerja terbaik.
FileReader tidak akan membiarkan Anda menentukan penyandian, gunakan InputStreamReader
sebaliknya jika Anda perlu menentukannya:
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();
}
Jika Anda mengimpor file ini dari Windows, mungkin ada encoding ANSI (Cp1252), jadi Anda harus menentukan encoding.
Saya mendokumentasikan dan menguji 10 cara berbeda untuk membaca file di Java dan kemudian menjalankannya satu sama lain dengan membuat mereka membaca file tes dari 1KB hingga 1GB. Berikut adalah 3 metode membaca file tercepat untuk membaca file tes 1GB.
Perhatikan bahwa ketika menjalankan tes kinerja saya tidak mengeluarkan apa pun ke konsol karena itu akan benar-benar memperlambat tes. Saya hanya ingin menguji kecepatan membaca mentah.
1) java.nio.file.Files.readAllBytes ()
Diuji di Java 7, 8, 9. Ini secara keseluruhan adalah metode tercepat. Membaca file 1GB secara konsisten hanya di bawah 1 detik.
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 ()
Ini diuji dengan sukses di Java 8 dan 9 tetapi tidak akan berhasil di Java 7 karena kurangnya dukungan untuk ekspresi lambda. Butuh waktu sekitar 3,5 detik untuk membaca dalam file 1GB yang menempatkannya di posisi kedua sejauh membaca file yang lebih besar.
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
Diuji untuk bekerja di Java 7, 8, 9. Ini membutuhkan waktu sekitar 4,5 detik untuk membaca dalam file uji 1GB.
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);
}
}
}
Anda dapat menemukan peringkat lengkap untuk semua 10 metode membaca file di sini .
System.out.print/println()
sini; Anda juga mengasumsikan file tersebut akan masuk ke memori dalam dua kasus pertama Anda.
Di Jawa 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
untuk menghindari pengecualian yang dicentang diCharset.forName("UTF-8")
Di Java 8, ada juga alternatif untuk menggunakan Files.lines()
. Jika sumber input Anda bukan file tetapi sesuatu yang lebih abstrak seperti Reader
atau InputStream
, Anda dapat mengalirkan baris melalui metode BufferedReader
s lines()
.
Sebagai contoh:
try (BufferedReader reader = new BufferedReader(...)) {
reader.lines().forEach(line -> processLine(line));
}
akan memanggil processLine()
setiap jalur input yang dibaca oleh BufferedReader
.
Untuk membaca file dengan 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();
}
}
}
Anda dapat menggunakan kelas Scanner
Scanner sc=new Scanner(file);
sc.nextLine();
Scanner
baik-baik saja, tetapi jawaban ini tidak menyertakan kode lengkap untuk menggunakannya dengan benar.
BufferedReader.readLine()
tentu saja beberapa kali lebih cepat. Jika Anda berpikir sebaliknya, berikan alasan Anda.
Anda perlu menggunakan readLine()
metode ini di class BufferedReader
. Buat objek baru dari kelas itu dan operasikan metode ini padanya dan simpan ke string.
Cara yang jelas untuk mencapai ini,
Sebagai contoh:
Jika ada dataFile.txt
di direktori Anda saat ini
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");
}
Ini bekerja untuk saya. Semoga ini akan membantu Anda juga.
Anda dapat menggunakan stream untuk melakukannya lebih tepat:
Files.lines(Paths.get("input.txt")).forEach(s -> stringBuffer.append(s);
Saya biasanya melakukan rutinitas membaca langsung:
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) {
}
}
}
Anda dapat menggunakan kode ini:
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();
}
}
}
Dengan menggunakan paket org.apache.commons.io , itu memberikan kinerja lebih, terutama dalam kode legacy yang menggunakan Java 6 dan di bawah.
Java 7 memiliki API yang lebih baik dengan penanganan pengecualian yang lebih sedikit dan metode yang lebih berguna:
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>
Anda juga dapat menggunakan 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)
adalah metode yang sudah usang. Selain itu, metode ini memanggil IOUtils.readLines
, yang menggunakan BufferedReader dan ArrayList. Ini bukan metode baris demi baris, dan tentu saja bukan metode yang praktis untuk membaca beberapa GB.