Saat googling, saya melihat bahwa menggunakan java.io.File#length()
bisa lambat.
FileChannel
memiliki size()
metode yang tersedia juga.
Apakah ada cara yang efisien di java untuk mendapatkan ukuran file?
Saat googling, saya melihat bahwa menggunakan java.io.File#length()
bisa lambat.
FileChannel
memiliki size()
metode yang tersedia juga.
Apakah ada cara yang efisien di java untuk mendapatkan ukuran file?
Jawaban:
Baiklah, saya mencoba mengukurnya dengan kode di bawah ini:
Untuk menjalankan = 1 dan iterasi = 1 metode URL paling cepat diikuti oleh saluran. Saya menjalankan ini dengan jeda segar sekitar 10 kali. Jadi untuk akses satu kali, menggunakan URL adalah cara tercepat yang dapat saya pikirkan:
Untuk menjalankan = 5 dan iterasi = 50 gambarnya berbeda.
File harus caching panggilan ke sistem file, sementara saluran dan URL memiliki beberapa overhead.
Kode:
sumber
stream.available()
tidak mengembalikan panjang file. Ini mengembalikan jumlah byte yang tersedia untuk dibaca tanpa memblokir aliran lainnya. Jumlah byte tidak selalu sama dengan panjang file. Untuk mendapatkan panjang sebenarnya dari aliran, Anda benar-benar perlu membacanya (dan menghitung byte baca sementara itu).Benchmark yang diberikan oleh GHad mengukur banyak hal lain (seperti refleksi, objek instantiating, dll.) Selain mendapatkan panjangnya. Jika kita mencoba untuk menyingkirkan hal-hal ini maka untuk satu panggilan saya dapatkan waktu berikut dalam mikrodetik:
Untuk 100 berjalan dan 10.000 iterasi saya dapatkan:
Saya memang menjalankan kode yang dimodifikasi berikut memberikan sebagai argumen nama file 100MB.
sumber
Semua kasus uji dalam posting ini cacat karena mereka mengakses file yang sama untuk setiap metode yang diuji. Jadi, cache caching menghasilkan tes 2 dan 3. Untuk membuktikan pendapat saya, saya mengambil test case yang disediakan oleh GHAD dan mengubah urutan enumerasi dan berikut hasilnya.
Melihat hasil, saya pikir File.length () adalah pemenangnya.
Urutan tes adalah urutan output. Anda bahkan dapat melihat waktu yang dibutuhkan pada mesin saya bervariasi antara eksekusi tetapi File.Length () ketika tidak pertama, dan menimbulkan akses disk pertama dimenangkan.
sumber
Ketika saya memodifikasi kode Anda untuk menggunakan file yang diakses oleh jalur absolut alih-alih sumber daya, saya mendapatkan hasil yang berbeda (untuk 1 run, 1 iterasi, dan file 100.000 byte - kali untuk file 10 byte identik dengan 100.000 byte )
PANJANG jumlah: 33, per Iterasi: 33.0
Jumlah CHANNEL: 3626, per Iterasi: 3626.0
Jumlah URL: 294, per Iterasi: 294.0
sumber
Menanggapi tolok ukur rgrig, waktu yang dibutuhkan untuk membuka / menutup instance FileChannel & RandomAccessFile juga perlu diperhitungkan, karena kelas-kelas ini akan membuka aliran untuk membaca file.
Setelah memodifikasi patokan, saya mendapat hasil ini untuk 1 iterasi pada file 85MB:
Untuk 10.000 iterasi pada file yang sama:
Jika yang Anda butuhkan adalah ukuran file, file.length () adalah cara tercepat untuk melakukannya. Jika Anda berencana untuk menggunakan file untuk tujuan lain seperti membaca / menulis, maka RAF tampaknya menjadi taruhan yang lebih baik. Hanya saja jangan lupa untuk menutup koneksi file :-)
sumber
Saya mengalami masalah yang sama. Saya perlu mendapatkan ukuran file dan tanggal modifikasi dari 90.000 file di jaringan berbagi. Menggunakan Java, dan menjadi seminimal mungkin, itu akan memakan waktu yang sangat lama. (Saya perlu mendapatkan URL dari file, dan jalur objek juga. Jadi agak bervariasi, tetapi lebih dari satu jam.) Saya kemudian menggunakan executable Win32 asli, dan melakukan tugas yang sama, hanya membuang file jalan, dimodifikasi, dan ukuran ke konsol, dan dieksekusi itu dari Jawa. Kecepatannya luar biasa. Proses asli, dan penanganan string saya untuk membaca data dapat memproses lebih dari 1000 item per detik.
Jadi, meskipun orang-orang di bawah peringkat komentar di atas, ini adalah solusi yang valid, dan memang memecahkan masalah saya. Dalam kasus saya, saya tahu folder yang saya butuhkan ukuran sebelumnya, dan saya bisa meneruskannya di baris perintah ke aplikasi win32 saya. Saya beralih dari jam ke proses direktori ke menit.
Masalahnya juga tampaknya khusus untuk Windows. OS X tidak memiliki masalah yang sama dan dapat mengakses informasi file jaringan secepat OS dapat melakukannya.
Penanganan File Java di Windows sangat buruk. Akses disk lokal untuk file baik-baik saja. Itu hanya jaringan berbagi yang menyebabkan kinerja yang mengerikan. Windows dapat memperoleh info tentang jaringan berbagi dan menghitung ukuran total dalam waktu kurang dari satu menit juga.
--Ben
sumber
Jika Anda ingin ukuran file beberapa file dalam direktori, gunakan
Files.walkFileTree
. Anda dapat memperoleh ukuran dariBasicFileAttributes
yang akan Anda terima.Ini jauh lebih cepat daripada memanggil
.length()
hasilFile.listFiles()
atau menggunakanFiles.size()
hasilFiles.newDirectoryStream()
. Dalam kasus pengujian saya sekitar 100 kali lebih cepat.sumber
Files.walkFileTree
tersedia di Android 26+.Sebenarnya, saya pikir "ls" mungkin lebih cepat. Pasti ada beberapa masalah di Jawa yang berhubungan dengan mendapatkan info File. Sayangnya tidak ada metode rekursif aman yang setara untuk Windows. (DIR / S cmd.exe bisa membingungkan dan menghasilkan kesalahan dalam loop tak terbatas)
Di XP, mengakses server di LAN, saya butuh 5 detik di Windows untuk mendapatkan jumlah file dalam folder (33.000), dan ukuran total.
Ketika saya mengulanginya secara berulang di Jawa, saya membutuhkan waktu lebih dari 5 menit. Saya mulai mengukur waktu yang diperlukan untuk melakukan file.length (), file.lastModified (), dan file.toURI () dan apa yang saya temukan adalah bahwa 99% dari waktu saya diambil oleh 3 panggilan itu. 3 panggilan yang sebenarnya harus saya lakukan ...
Perbedaan untuk 1000 file adalah 15ms lokal versus 1800ms di server. Pemindaian jalur server di Jawa sangat lambat. Jika OS asli bisa cepat memindai folder yang sama, mengapa tidak bisa Java?
Sebagai tes yang lebih lengkap, saya menggunakan WineMerge di XP untuk membandingkan tanggal yang dimodifikasi, dan ukuran file di server versus file secara lokal. Ini mengulangi seluruh pohon direktori dari 33.000 file di setiap folder. Total waktu, 7 detik. java: lebih dari 5 menit.
Jadi pernyataan dan pertanyaan asli dari OP itu benar, dan valid. Ini kurang terlihat ketika berhadapan dengan sistem file lokal. Melakukan perbandingan folder secara lokal dengan 33.000 item membutuhkan waktu 3 detik di WinMerge, dan memakan waktu 32 detik secara lokal di Java. Jadi sekali lagi, java versus asli adalah perlambatan 10x dalam tes dasar ini.
Java 1.6.0_22 (terbaru), Gigabit LAN, dan koneksi jaringan, ping kurang dari 1ms (keduanya dalam switch yang sama)
Java lambat.
sumber
Dari tolok ukur GHad, ada beberapa masalah yang disebutkan orang:
1> Seperti yang disebutkan BalusC: stream.available () mengalir dalam kasus ini.
Karena tersedia () mengembalikan estimasi jumlah byte yang dapat dibaca (atau dilompati) dari aliran input ini tanpa menghalangi dengan permohonan metode berikutnya untuk aliran input ini.
Jadi 1 untuk menghapus URL pendekatan ini.
2> Seperti yang disebutkan StuartH - urutan tes juga membuat perbedaan cache, jadi keluarkan dengan menjalankan tes secara terpisah.
Sekarang mulailah tes:
Ketika CHANNEL satu dijalankan sendiri:
Ketika PANJANG satu berjalan sendiri:
Jadi sepertinya PANJANG adalah pemenangnya di sini:
sumber