Saya perlu membaca file teks besar sekitar 5-6 GB baris demi baris menggunakan Java.
Bagaimana saya bisa melakukan ini dengan cepat?
java
performance
file-io
io
garbage-collection
manoj singh
sumber
sumber
Jawaban:
Pola yang umum digunakan
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.UPDATE: Di Java 8 Anda bisa melakukannya
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.
sumber
for(String line = br.readLine(); line != null; line = br.readLine())
Btw, di Jawa 8 Anda bisa melakukantry( Stream<String> lines = Files.lines(...) ){ for( String line : (Iterable<String>) lines::iterator ) { ... } }
yang sulit untuk tidak membenci.Lihatlah blog ini:
sumber
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:
Mencetak semua baris dalam file:
sumber
StandardCharsets.UTF_8
, gunakanStream<String>
untuk keringkasan, dan hindari menggunakanforEach()
dan terutamaforEachOrdered()
kecuali ada alasannya.forEach(this::process)
, tetapi akan jelek jika Anda menulis blok kode sebagai lambdas di dalamnyaforEach()
.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.
Ini adalah versi Groovy, dengan penanganan kesalahan penuh:
sumber
ByteArrayInputStream
dengan string literal hubungannya dengan membaca file teks besar?Di Java 8, Anda bisa melakukan:
Beberapa catatan: Aliran dikembalikan oleh
Files.lines
(tidak seperti kebanyakan aliran) perlu ditutup. Untuk alasan yang disebutkan di sini saya menghindari penggunaanforEach()
. Kode aneh(Iterable<String>) lines::iterator
melemparkan Stream ke Iterable.sumber
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, menggunakanFiles.newBufferedReader
alih-alihFiles.lines
dan berulang kali meneleponreadLine()
hingganull
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:
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. CobaSystem.out.println(line)
cetak teksnya.Catatan Sisi: .txt adalah teks jenis file.
sumber
BufferedReader.readLine()
, dan dia meminta metode berkinerja terbaik.FileReader tidak akan membiarkan Anda menentukan penyandian, gunakan
InputStreamReader
sebaliknya jika Anda perlu menentukannya:Jika Anda mengimpor file ini dari Windows, mungkin ada encoding ANSI (Cp1252), jadi Anda harus menentukan encoding.
sumber
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.
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.
3) BufferedReader
Diuji untuk bekerja di Java 7, 8, 9. Ini membutuhkan waktu sekitar 4,5 detik untuk membaca dalam file uji 1GB.
Anda dapat menemukan peringkat lengkap untuk semua 10 metode membaca file di sini .
sumber
System.out.print/println()
sini; Anda juga mengasumsikan file tersebut akan masuk ke memori dalam dua kasus pertama Anda.Di Jawa 7:
sumber
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 sepertiReader
atauInputStream
, Anda dapat mengalirkan baris melalui metodeBufferedReader
slines()
.Sebagai contoh:
akan memanggil
processLine()
setiap jalur input yang dibaca olehBufferedReader
.sumber
Untuk membaca file dengan Java 8
sumber
Anda dapat menggunakan kelas Scanner
sumber
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 diclass BufferedReader
. Buat objek baru dari kelas itu dan operasikan metode ini padanya dan simpan ke string.BufferReader Javadoc
sumber
Cara yang jelas untuk mencapai ini,
Sebagai contoh:
Jika ada
dataFile.txt
di direktori Anda saat iniOutput seperti di bawah ini,
sumber
Java 9:
sumber
System.getProperty("os.name").equals("Linux")
==
!Ini bekerja untuk saya. Semoga ini akan membantu Anda juga.
sumber
Anda dapat menggunakan stream untuk melakukannya lebih tepat:
sumber
Saya biasanya melakukan rutinitas membaca langsung:
sumber
Anda dapat menggunakan kode ini:
sumber
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:
Maven
sumber
Anda juga dapat menggunakan Apache Commons IO :
sumber
FileUtils.readLines(file)
adalah metode yang sudah usang. Selain itu, metode ini memanggilIOUtils.readLines
, yang menggunakan BufferedReader dan ArrayList. Ini bukan metode baris demi baris, dan tentu saja bukan metode yang praktis untuk membaca beberapa GB.