Saya telah banyak mencari cara tercepat untuk membaca dan menulis lagi file besar (0,5 - 1 GB) di java dengan memori terbatas (sekitar 64MB). Setiap baris dalam file mewakili sebuah catatan, jadi saya perlu mendapatkannya baris demi baris. File tersebut adalah file teks biasa.
Saya mencoba BufferedReader dan BufferedWriter tetapi tampaknya bukan pilihan terbaik. Dibutuhkan sekitar 35 detik untuk membaca dan menulis file berukuran 0.5 GB, hanya baca tulis tanpa pemrosesan. Saya pikir bottleneck di sini adalah menulis karena membaca saja membutuhkan waktu sekitar 10 detik.
Saya mencoba membaca array byte, tetapi kemudian mencari baris di setiap array yang dibaca membutuhkan lebih banyak waktu.
Ada saran yang bisa diberikan? Terima kasih
Saya menduga masalah Anda yang sebenarnya adalah bahwa Anda memiliki perangkat keras yang terbatas dan apa yang Anda lakukan adalah perangkat lunak tidak akan membuat banyak perbedaan. Jika Anda memiliki banyak memori dan CPU, trik yang lebih canggih dapat membantu, tetapi jika Anda hanya menunggu di hard drive Anda karena file tidak di-cache, itu tidak akan membuat banyak perbedaan.
BTW: 500 MB dalam 10 detik atau 50 MB/detik adalah kecepatan baca yang umum untuk HDD.
Coba jalankan yang berikut ini untuk melihat pada titik mana sistem Anda tidak dapat men-cache file secara efisien.
public static void main(String... args) throws IOException {
for (int mb : new int[]{50, 100, 250, 500, 1000, 2000})
testFileSize(mb);
}
private static void testFileSize(int mb) throws IOException {
File file = File.createTempFile("test", ".txt");
file.deleteOnExit();
char[] chars = new char[1024];
Arrays.fill(chars, 'A');
String longLine = new String(chars);
long start1 = System.nanoTime();
PrintWriter pw = new PrintWriter(new FileWriter(file));
for (int i = 0; i < mb * 1024; i++)
pw.println(longLine);
pw.close();
long time1 = System.nanoTime() - start1;
System.out.printf("Took %.3f seconds to write to a %d MB, file rate: %.1f MB/s%n",
time1 / 1e9, file.length() >> 20, file.length() * 1000.0 / time1);
long start2 = System.nanoTime();
BufferedReader br = new BufferedReader(new FileReader(file));
for (String line; (line = br.readLine()) != null; ) {
}
br.close();
long time2 = System.nanoTime() - start2;
System.out.printf("Took %.3f seconds to read to a %d MB file, rate: %.1f MB/s%n",
time2 / 1e9, file.length() >> 20, file.length() * 1000.0 / time2);
file.delete();
}
Pada mesin Linux dengan banyak memori.
Took 0.395 seconds to write to a 50 MB, file rate: 133.0 MB/s
Took 0.375 seconds to read to a 50 MB file, rate: 140.0 MB/s
Took 0.669 seconds to write to a 100 MB, file rate: 156.9 MB/s
Took 0.569 seconds to read to a 100 MB file, rate: 184.6 MB/s
Took 1.585 seconds to write to a 250 MB, file rate: 165.5 MB/s
Took 1.274 seconds to read to a 250 MB file, rate: 206.0 MB/s
Took 2.513 seconds to write to a 500 MB, file rate: 208.8 MB/s
Took 2.332 seconds to read to a 500 MB file, rate: 225.1 MB/s
Took 5.094 seconds to write to a 1000 MB, file rate: 206.0 MB/s
Took 5.041 seconds to read to a 1000 MB file, rate: 208.2 MB/s
Took 11.509 seconds to write to a 2001 MB, file rate: 182.4 MB/s
Took 9.681 seconds to read to a 2001 MB file, rate: 216.8 MB/s
Pada mesin windows dengan banyak memori.
Took 0.376 seconds to write to a 50 MB, file rate: 139.7 MB/s
Took 0.401 seconds to read to a 50 MB file, rate: 131.1 MB/s
Took 0.517 seconds to write to a 100 MB, file rate: 203.1 MB/s
Took 0.520 seconds to read to a 100 MB file, rate: 201.9 MB/s
Took 1.344 seconds to write to a 250 MB, file rate: 195.4 MB/s
Took 1.387 seconds to read to a 250 MB file, rate: 189.4 MB/s
Took 2.368 seconds to write to a 500 MB, file rate: 221.8 MB/s
Took 2.454 seconds to read to a 500 MB file, rate: 214.1 MB/s
Took 4.985 seconds to write to a 1001 MB, file rate: 210.7 MB/s
Took 5.132 seconds to read to a 1001 MB file, rate: 204.7 MB/s
Took 10.276 seconds to write to a 2003 MB, file rate: 204.5 MB/s
Took 9.964 seconds to read to a 2003 MB file, rate: 210.9 MB/s
Hal pertama yang akan saya coba adalah meningkatkan ukuran buffer dari BufferedReader dan BufferedWriter. Ukuran buffer default tidak didokumentasikan, tetapi setidaknya di Oracle VM ukurannya adalah 8192 karakter, yang tidak akan membawa banyak keuntungan kinerja.
Jika Anda hanya perlu membuat salinan file (dan tidak memerlukan akses aktual ke data), saya akan membuang pendekatan Reader/Writer dan bekerja secara langsung dengan InputStream dan OutputStream menggunakan array byte sebagai buffer:
FileInputStream fis = new FileInputStream("d:/test.txt");
FileOutputStream fos = new FileOutputStream("d:/test2.txt");
byte[] b = new byte[bufferSize];
int r;
while ((r=fis.read(b))>=0) {
fos.write(b, 0, r);
}
fis.close();
fos.close();
atau benar-benar menggunakan NIO:
FileChannel in = new RandomAccessFile("d:/test.txt", "r").getChannel();
FileChannel out = new RandomAccessFile("d:/test2.txt", "rw").getChannel();
out.transferFrom(in, 0, Long.MAX_VALUE);
in.close();
out.close();
Ketika melakukan benchmarking metode penyalinan yang berbeda, saya memiliki perbedaan (durasi) yang jauh lebih besar di antara setiap menjalankan benchmark daripada di antara implementasi yang berbeda. I/O caching (baik pada level OS dan cache hard disk) memainkan peran besar di sini dan sangat sulit untuk mengatakan mana yang lebih cepat. Pada perangkat keras saya, menyalin file teks 1GB baris demi baris menggunakan BufferedReader dan BufferedWriter membutuhkan waktu kurang dari 5 detik di beberapa proses dan lebih dari 30 detik di proses lainnya.
Saya akan merekomendasikan untuk melihat kelas-kelas dalam paket java.nio
. IO non-blocking mungkin lebih cepat untuk soket:
http://docs.oracle.com/javase/6/docs/api/java/nio/package-summary.html
Artikel ini memiliki tolok ukur yang mengatakan bahwa itu benar:
http://vanillajava.blogspot.com/2010/07/java-nio-is-faster-than-java-io-for.html