Ini adalah versi tercepat yang saya temukan sejauh ini, sekitar 6 kali lebih cepat daripada readLines. Pada file log 150MB ini membutuhkan 0,35 detik, dibandingkan 2,40 detik saat menggunakan readLines (). Hanya untuk bersenang-senang, perintah linux 'wc -l membutuhkan waktu 0,15 detik.
public static int countLinesOld(String filename) throws IOException {
InputStream is = new BufferedInputStream(new FileInputStream(filename));
try {
byte[] c = new byte[1024];
int count = 0;
int readChars = 0;
boolean empty = true;
while ((readChars = is.read(c)) != -1) {
empty = false;
for (int i = 0; i < readChars; ++i) {
if (c[i] == '\n') {
++count;
}
}
}
return (count == 0 && !empty) ? 1 : count;
} finally {
is.close();
}
}
EDIT, 9 1/2 tahun kemudian: Praktis saya tidak punya pengalaman java, tapi bagaimanapun saya telah mencoba untuk membandingkan kode ini dengan LineNumberReader
solusi di bawah ini karena itu mengganggu saya bahwa tidak ada yang melakukannya. Tampaknya terutama untuk file besar solusi saya lebih cepat. Meskipun tampaknya perlu beberapa kali hingga pengoptimal melakukan pekerjaan yang layak. Saya telah bermain sedikit dengan kode, dan telah menghasilkan versi baru yang secara konsisten tercepat:
public static int countLinesNew(String filename) throws IOException {
InputStream is = new BufferedInputStream(new FileInputStream(filename));
try {
byte[] c = new byte[1024];
int readChars = is.read(c);
if (readChars == -1) {
// bail out if nothing to read
return 0;
}
// make it easy for the optimizer to tune this loop
int count = 0;
while (readChars == 1024) {
for (int i=0; i<1024;) {
if (c[i++] == '\n') {
++count;
}
}
readChars = is.read(c);
}
// count remaining characters
while (readChars != -1) {
System.out.println(readChars);
for (int i=0; i<readChars; ++i) {
if (c[i] == '\n') {
++count;
}
}
readChars = is.read(c);
}
return count == 0 ? 1 : count;
} finally {
is.close();
}
}
Resuls benchmark untuk file teks 1.3GB, sumbu y dalam hitungan detik. Saya telah melakukan 100 berjalan dengan file yang sama, dan diukur masing-masing berjalan dengan System.nanoTime()
. Anda dapat melihat bahwa countLinesOld
memiliki beberapa outlier, dan countLinesNew
tidak memiliki outlier dan meskipun hanya sedikit lebih cepat, perbedaannya signifikan secara statistik. LineNumberReader
jelas lebih lambat.
Saya telah menerapkan solusi lain untuk masalah ini, saya merasa lebih efisien dalam menghitung baris:
sumber
LineNumberReader
'slineNumber
lapangan adalah bilangan bulat ... Akan bukan hanya membungkus untuk file lama dari Integer.MAX_VALUE? Kenapa repot-repot melewatkan waktu lama di sini?wc -l
menghitung jumlah karakter baris baru dalam file. Ini berfungsi karena setiap baris diakhiri dengan baris baru, termasuk baris terakhir dalam file. Setiap baris memiliki karakter baris baru, termasuk baris kosong, sehingga jumlah baris baris baru == jumlah baris dalam file. Sekarang,lineNumber
variabel dalamFileNumberReader
juga mewakili jumlah karakter baris baru yang terlihat. Itu dimulai dari nol, sebelum baris baru ditemukan, dan ditingkatkan dengan setiap baris baris baru dilihat. Jadi jangan menambahkan satu ke nomor baris.wc -l
juga cara melaporkan jenis file ini. Lihat juga stackoverflow.com/questions/729692/…wc -l
akan kembali 1. Saya menyimpulkan bahwa semua metode memiliki kekurangan, dan menerapkan satu berdasarkan pada bagaimana saya ingin berperilaku, lihat jawaban saya yang lain di sini.Jawaban yang diterima memiliki kesalahan satu demi satu untuk file multi-baris yang tidak berakhir pada baris baru. File satu baris yang berakhir tanpa baris baru akan mengembalikan 1, tetapi file dua baris yang berakhir tanpa baris baru akan mengembalikan 1 juga. Berikut ini adalah implementasi dari solusi yang diterima yang memperbaikinya. Pemeriksaan endsWithoutNewLine sia-sia untuk semuanya kecuali membaca akhir, tetapi harus sepele waktu bijaksana dibandingkan dengan fungsi keseluruhan.
sumber
Dengan java-8, Anda dapat menggunakan stream:
sumber
Jawaban dengan hitungan metode () di atas memberi saya kesalahan perhitungan baris jika file tidak memiliki baris baru di akhir file - gagal menghitung baris terakhir dalam file.
Metode ini bekerja lebih baik untuk saya:
sumber
cnt
.Saya tahu ini adalah pertanyaan lama, tetapi solusi yang diterima tidak cocok dengan yang saya butuhkan. Jadi, saya memperbaikinya untuk menerima berbagai terminator garis (bukan hanya umpan baris) dan menggunakan pengkodean karakter yang ditentukan (bukan ISO-8859- n ). Semua dalam satu metode (refactor yang sesuai):
Solusi ini sebanding dalam kecepatannya dengan solusi yang diterima, sekitar 4% lebih lambat dalam pengujian saya (meskipun tes waktu di Jawa sangat tidak dapat diandalkan).
sumber
Saya menguji metode di atas untuk menghitung garis dan inilah pengamatan saya untuk metode yang berbeda seperti yang diuji pada sistem saya
Ukuran File: 1,6 Gb Metode:
Selain itu Pendekatan Java8 tampaknya cukup berguna:
sumber
Diuji pada JDK8_u31. Tetapi memang kinerjanya lambat dibandingkan dengan metode ini:
Diuji dan sangat cepat.
sumber
Stream<String> - Time consumed: 122796351 Stream<String> - Num lines: 109808 Method - Time consumed: 12838000 Method - Num lines: 1
Dan jumlah kalimatnya bahkan salahBufferedInputStream
kapan Anda akan membaca ke buffer Anda sendiri. Selain itu, bahkan jika metode Anda mungkin memiliki sedikit keunggulan kinerja, metode ini kehilangan fleksibilitas, karena tidak lagi mendukung satu-satunya\r
terminator (MacOS lama) dan tidak mendukung setiap penyandian.Cara mudah menggunakan Scanner
sumber
Saya menyimpulkan bahwa
wc -l
: metode penghitungan baris baru baik-baik saja tetapi mengembalikan hasil non-intuitif pada file di mana baris terakhir tidak berakhir dengan baris baru.Dan solusi @ er.vikas berdasarkan LineNumberReader tetapi menambahkan satu ke jumlah baris menghasilkan hasil yang tidak intuitif pada file di mana baris terakhir diakhiri dengan baris baru.
Karena itu saya membuat algo yang menangani sebagai berikut:
Dan terlihat seperti ini:
Jika Anda menginginkan hasil yang intuitif, Anda dapat menggunakan ini. Jika Anda hanya ingin
wc -l
kompatibilitas, gunakan solusi sederhana @ er.vikas, tapi jangan tambahkan satu ke hasilnya dan coba lagi lewati:sumber
Bagaimana kalau menggunakan kelas Proses dari dalam kode Java? Dan kemudian membaca output dari perintah.
Namun perlu dicoba. Akan memposting hasilnya.
sumber
Jika Anda tidak memiliki struktur indeks apa pun, Anda tidak akan bisa menyelesaikan pembacaan file lengkap. Tetapi Anda dapat mengoptimalkannya dengan menghindari membacanya baris demi baris dan menggunakan regex untuk mencocokkan semua terminator baris.
sumber
Solusi lucu ini bekerja sangat baik sebenarnya!
sumber
Pada sistem berbasis Unix, gunakan
wc
perintah pada baris perintah.sumber
Satu-satunya cara untuk mengetahui berapa banyak baris yang ada dalam file adalah dengan menghitungnya. Anda tentu saja dapat membuat metrik dari data Anda, memberi Anda rata-rata panjang satu baris dan kemudian mendapatkan ukuran file dan membaginya dengan rata-rata. panjang tapi itu tidak akan akurat.
sumber
Kode Dioptimalkan Terbaik untuk file multi-baris yang tidak memiliki karakter baris baru ('\ n') di EOF.
sumber
Pemindai dengan regex:
Belum melihatnya.
sumber
jika Anda menggunakan ini
Anda tidak dapat lari ke baris angka besar, menyukai baris 100K, karena kembali dari reader.getLineNumber adalah int. Anda memerlukan tipe data yang panjang untuk memproses baris maksimum ..
sumber
int
dapat menyimpan nilai hingga, sekitar 2 miliar. Jika Anda memuat file dengan lebih dari 2 miliar baris, Anda memiliki masalah overflow. Yang mengatakan, jika Anda memuat file teks yang tidak diindeks dengan lebih dari dua miliar baris, Anda mungkin memiliki masalah lain.