Saya baru saja menyelesaikan Hasil Tes yang menyediakan tes kinerja untuk banyak jawaban. Tidak mengherankan semua jawaban berbasis NIO berkinerja terbaik. Jawaban umum jelas berkinerja terburuk dengan lebih dari dua kali panjang lari.
Brett Ryan
2
Java8: Files.walk?
Benj
Jawaban:
327
Java 8 menyediakan aliran yang bagus untuk memproses semua file dalam pohon.
Ini memberikan cara alami untuk melintasi file. Karena ini adalah streaming, Anda dapat melakukan semua operasi streaming yang bagus pada hasil seperti batas, pengelompokan, pemetaan, keluar lebih awal, dll.
UPDATE : Saya mungkin menunjukkan ada juga Files.find yang mengambil BiPredicate yang bisa lebih efisien jika Anda perlu memeriksa atribut file.
Perhatikan bahwa sementara JavaDoc menghindari bahwa metode ini bisa lebih efisien daripada Files.walk secara efektif identik, perbedaan dalam kinerja dapat diamati jika Anda juga mengambil atribut file dalam filter Anda. Pada akhirnya, jika Anda perlu memfilter pada atribut menggunakan Files.find , sebaliknya gunakan Files.walk , sebagian besar karena ada kelebihan dan lebih nyaman.
Salah satu contoh yang dapat menunjukkan keajaiban pemrograman fungsional bahkan untuk pemula.
Johnny
2
Bagaimana kinerja ini dibandingkan dengan metode pra-java 8? Traversal direktori saya saat ini terlalu lambat dan saya sedang mencari sesuatu yang akan mempercepatnya.
Sridhar Sarnobat
1
Saya menulis beberapa tes yang mengandung sebagian besar varian dalam jawaban yang diberikan. Sejauh ini, tampaknya menggunakan Files.walkdengan aliran paralel adalah yang terbaik, diikuti oleh Files.walkFileTreeyang hanya sedikit lebih lambat. Jawaban yang diterima menggunakan commons-io sejauh ini paling lambat oleh tes saya menjadi 4 kali lebih lambat.
Brett Ryan
1
@ BrettRyan, saya mencoba solusi Anda, tetapi saya mendapatkan pengecualian Exception in thread "main" java.io.UncheckedIOException: java.nio.file.AccessDeniedException. Bagaimana saya bisa memperbaikinya
Kachna
5
Bagaimana cara saya mendapatkan daftar file yang sebenarnya dari ini?
Sunting: Anda dapat memeriksa di sini untuk benchmark dari berbagai pendekatan. Tampaknya pendekatan commons-io lambat, jadi pilih yang lebih cepat dari sini (jika itu penting)
FYI / TLDR: jika Anda hanya ingin mendaftar semua file secara rekursif tanpa penyaringan, lakukan FileUtils.listFiles(dir, TrueFileFilter.INSTANCE, TrueFileFilter.INSTANCE), di mana dirobjek File yang menunjuk ke direktori dasar.
andronikus
2
Anda mungkin ingin mempertimbangkan untuk menggunakan listFilesAndDirs(), karena listFiles()tidak mengembalikan folder kosong.
schnatterer
1
@ MikeFHay Melihat kode FileUtils, saya pikir itu akan menjadi FileUtils.listFiles(dir, true, true). menggunakan FileUtils.listFiles(dir, null, true)akan membuang Pengecualian, sementara FileUtils.listFiles(dir, true, null)akan daftar semua file tanpa melihat ke subdirektori.
ocramot
Bagaimana dengan perpustakaan asli JDK? Saya bisa menerapkan ini dengan mudah tetapi saya hanya akan menjadi C&P dari tempat lain
Christian Bongiorno
1
Saya sedang melakukan beberapa tes bersama, tetapi sejauh ini ini tampaknya melakukan 4 kali lebih lambat daripada menggunakan alternatif JDK8 atau JDK7. Symlinks juga terbukti bermasalah dengan pendekatan ini, terutama di mana mereka menautkan ke direktori yang lebih tinggi di pohon, ini menyebabkan metode tidak pernah kembali, ini dapat dihindari dengan menangani filter, tetapi sayangnya symlinks sendiri tidak dikunjungi walaupun file.
Brett Ryan
138
// Siap untuk berlari
import java.io.File;publicclassFilewalker{publicvoid walk(String path ){File root =newFile( path );File[] list = root.listFiles();if(list ==null)return;for(File f : list ){if( f.isDirectory()){
walk( f.getAbsolutePath());System.out.println("Dir:"+ f.getAbsoluteFile());}else{System.out.println("File:"+ f.getAbsoluteFile());}}}publicstaticvoid main(String[] args){Filewalker fw =newFilewalker();
fw.walk("c:\\");}}
Berhati-hatilah bahwa untuk tautan simbolik yang mengarah ke jalur yang lebih tinggi dalam hierarki jalur akan menyebabkan metode ini tidak pernah berakhir. Pertimbangkan jalur dengan symlink yang menunjuk -> ..
Brett Ryan
2
Ini pada dasarnya hanyalah implementasi Files.walkFileTree yang buruk. Saya akan merekomendasikan bahwa orang melihat FIles.walkFileTree daripada mencoba untuk menggulung sendiri ... Ini telah menangani masalah yang tepat @BrettRyan mengarahkannya.
Tyler Nichols
Terima kasih telah memasukkan impor java.io.File ;. Begitu banyak contoh lupa untuk memasukkan hal-hal namespace atau bahkan hal-hal tipe data membuat contoh titik awal pada perjalanan penemuan. Di sini contoh ini siap dijalankan. Terima kasih.
barrypicker
Path dapat bervariasi tergantung di mana file Filewalker berada. Gunakan "/", "./"atau "../"untuk direktori root, direktori kerja saat ini, dan direktori induk, masing
Jika Anda memberikan titik awal dan pengunjung file, itu akan memanggil berbagai metode pada pengunjung file saat berjalan melalui file di pohon file. Kami berharap orang untuk menggunakan ini jika mereka mengembangkan salinan rekursif, gerakan rekursif, penghapusan rekursif, atau operasi rekursif yang menetapkan izin atau melakukan operasi lain pada masing-masing file.
publicvoid list(File file){System.out.println(file.getName());File[] children = file.listFiles();for(File child : children){
list(child);}}
System.out.println ada di sana hanya untuk menunjukkan untuk melakukan sesuatu dengan file tersebut. tidak perlu membedakan antara file dan direktori, karena file normal hanya akan memiliki nol anak.
Silahkan! biarkan penelepon menginisialisasi daftar file sehingga tidak harus memeriksa nolnya setiap kali. Jika Anda ingin membuat metode kedua (publik) yang membuat daftar, panggil metode internal ini dan kembalikan daftar lengkap.
helios
1
Masa bodo. cek nol tidak terlalu mahal, kenyamanan + selain preferensi pribadi saya pikir dia akan mengerti intinya.
pstanton
Bisakah Anda menjelaskan sedikit lebih banyak?
uday
8
Saya pikir ini harus dilakukan:
File dir =newFile(dirname);String[] files = dir.list();
Dengan cara ini Anda memiliki file dan direktori. Sekarang gunakan rekursi dan lakukan hal yang sama untuk dirs ( Fileclass has isDirectory()method).
The jawaban yang diterima besar, namun itu rusak ketika Anda ingin melakukan IO dalam lambda.
Inilah yang dapat Anda lakukan jika tindakan Anda menyatakan IOExceptions.
Anda dapat memperlakukan aliran yang difilter sebagai Iterable, dan kemudian melakukan tindakan Anda secara teratur untuk setiap loop. Dengan cara ini, Anda tidak perlu menangani pengecualian di dalam lambda.
try(Stream<Path> pathStream =Files.walk(Paths.get(path)).filter(Files::isRegularFile)){for(Path file :(Iterable<Path>) pathStream::iterator){// something that throws IOExceptionFiles.copy(file,System.out);}}
Memposting contoh ini, karena saya mengalami kesulitan memahami cara melewati parameter nama file dalam contoh # 1 yang diberikan oleh Bryan, menggunakan foreach pada hasil-Stream -
Berdasarkan jawaban stacker. Berikut ini adalah solusi yang bekerja di JSP tanpa pustaka eksternal sehingga Anda dapat meletakkannya hampir di mana saja di server Anda:
<!DOCTYPE html><%@ page session="false"%><%@ page import="java.util.*"%><%@ page import="java.io.*"%><%@ page contentType="text/html; charset=UTF-8"%><%!publicList<String> files =newArrayList<String>();/**
Fills files array with all sub-files.
*/publicvoid walk(File root ){File[] list = root.listFiles();if(list ==null)return;for(File f : list ){if( f.isDirectory()){
walk( f );}else{
files.add(f.getAbsolutePath());}}}%><%
files.clear();File jsp =newFile(request.getRealPath(request.getServletPath()));File dir = jsp.getParentFile();
walk(dir);String prefixPath = dir.getAbsolutePath()+"/";%>
Meskipun mungkin berhasil, pertanyaannya adalah tentang penelusuran file, bukan rendering file yang diramban. Lebih baik paparkan algoritme Anda dengan demikian, bukan praktik yang disarankan untuk menyematkan logika bisnis di dalam JSP.
Samuel Kerrien
Itu tergantung apa yang Anda lakukan. Dalam aplikasi ukuran perusahaan Anda benar sekali. Jika Anda hanya memerlukan ini sebagai drop-in ke daftar sederhana dan mandiri, maka ini tidak masalah.
Jawaban:
Java 8 menyediakan aliran yang bagus untuk memproses semua file dalam pohon.
Ini memberikan cara alami untuk melintasi file. Karena ini adalah streaming, Anda dapat melakukan semua operasi streaming yang bagus pada hasil seperti batas, pengelompokan, pemetaan, keluar lebih awal, dll.
UPDATE : Saya mungkin menunjukkan ada juga Files.find yang mengambil BiPredicate yang bisa lebih efisien jika Anda perlu memeriksa atribut file.
Perhatikan bahwa sementara JavaDoc menghindari bahwa metode ini bisa lebih efisien daripada Files.walk secara efektif identik, perbedaan dalam kinerja dapat diamati jika Anda juga mengambil atribut file dalam filter Anda. Pada akhirnya, jika Anda perlu memfilter pada atribut menggunakan Files.find , sebaliknya gunakan Files.walk , sebagian besar karena ada kelebihan dan lebih nyaman.
UJI : Seperti yang diminta, saya telah memberikan perbandingan kinerja dari banyak jawaban. Lihat proyek Github yang berisi hasil dan uji kasus .
sumber
Files.walk
dengan aliran paralel adalah yang terbaik, diikuti olehFiles.walkFileTree
yang hanya sedikit lebih lambat. Jawaban yang diterima menggunakan commons-io sejauh ini paling lambat oleh tes saya menjadi 4 kali lebih lambat.Exception in thread "main" java.io.UncheckedIOException: java.nio.file.AccessDeniedException
. Bagaimana saya bisa memperbaikinyaFileUtils punya
iterateFiles
danlistFiles
metode. Cobalah mereka. (dari commons-io )Sunting: Anda dapat memeriksa di sini untuk benchmark dari berbagai pendekatan. Tampaknya pendekatan commons-io lambat, jadi pilih yang lebih cepat dari sini (jika itu penting)
sumber
FileUtils.listFiles(dir, TrueFileFilter.INSTANCE, TrueFileFilter.INSTANCE)
, di manadir
objek File yang menunjuk ke direktori dasar.listFilesAndDirs()
, karenalistFiles()
tidak mengembalikan folder kosong.FileUtils.listFiles(dir, true, true)
. menggunakanFileUtils.listFiles(dir, null, true)
akan membuang Pengecualian, sementaraFileUtils.listFiles(dir, true, null)
akan daftar semua file tanpa melihat ke subdirektori.// Siap untuk berlari
sumber
-> .
."/"
,"./"
atau"../"
untuk direktori root, direktori kerja saat ini, dan direktori induk, masingJava 7
akanmemiliki Files.walkFileTree :Sekarang ada seluruh tutorial Oracle untuk pertanyaan ini .
sumber
Tidak diperlukan perpustakaan eksternal.
Mengembalikan Koleksi sehingga Anda dapat melakukan apa pun yang Anda inginkan dengannya setelah panggilan.
sumber
Saya akan pergi dengan sesuatu seperti:
System.out.println ada di sana hanya untuk menunjukkan untuk melakukan sesuatu dengan file tersebut. tidak perlu membedakan antara file dan direktori, karena file normal hanya akan memiliki nol anak.
sumber
listFiles()
: "Jika pathname abstrak ini tidak menunjukkan direktori, maka metode ini kembalinull
."Saya lebih suka menggunakan antrian atas rekursi untuk jenis traversi sederhana ini:
sumber
cukup tulis sendiri menggunakan rekursi sederhana:
sumber
Saya pikir ini harus dilakukan:
Dengan cara ini Anda memiliki file dan direktori. Sekarang gunakan rekursi dan lakukan hal yang sama untuk dirs (
File
class hasisDirectory()
method).sumber
Dengan Java 7 Anda dapat menggunakan kelas berikut:
sumber
Di Java 8, sekarang kita dapat menggunakan utilitas File untuk menjalankan hierarki file. Sangat sederhana.
sumber
Kode ini siap dijalankan
sumber
Terlepas dari traversal rekursif seseorang dapat menggunakan pendekatan berbasis Pengunjung juga.
Kode di bawah ini menggunakan pendekatan berbasis Pengunjung untuk traversal. Diharapkan input ke program adalah direktori root untuk dilalui.
sumber
Anda dapat menggunakan kode di bawah ini untuk mendapatkan daftar file folder atau direktori tertentu secara rekursif.
sumber
The jawaban yang diterima besar, namun itu rusak ketika Anda ingin melakukan IO dalam lambda.
Inilah yang dapat Anda lakukan jika tindakan Anda menyatakan IOExceptions.
Anda dapat memperlakukan aliran yang difilter sebagai
Iterable
, dan kemudian melakukan tindakan Anda secara teratur untuk setiap loop. Dengan cara ini, Anda tidak perlu menangani pengecualian di dalam lambda.Menemukan trik itu di sini: https://stackoverflow.com/a/32668807/1207791
sumber
BFS non-rekursif dengan satu daftar (contoh khusus mencari file * .eml):
sumber
Versi saya (tentu saja saya bisa menggunakan built in walk di Java 8 ;-)):
sumber
Di sini solusi sederhana namun berfungsi sempurna menggunakan
recursion
:sumber
sumber
Saya datang dengan ini untuk mencetak semua file / nama file secara rekursif.
sumber
Contoh menampilkan * .csv file dalam direktori Subdirectories pencarian rekursif menggunakan Files.find () dari java.nio:
Memposting contoh ini, karena saya mengalami kesulitan memahami cara melewati parameter nama file dalam contoh # 1 yang diberikan oleh Bryan, menggunakan foreach pada hasil-Stream -
Semoga ini membantu.
sumber
Kotlin memiliki
FileTreeWalk
tujuan ini. Sebagai contoh:Akan menghasilkan daftar teks semua file non-direktori di bawah root yang diberikan, satu file per baris dengan path relatif ke root dan panjangnya.
sumber
Cara lain yang dapat Anda lakukan bahkan jika seseorang sudah menyediakan Java 8 walk.
Yang ini akan memberi Anda semua file secara rekursif
sumber
Berdasarkan jawaban stacker. Berikut ini adalah solusi yang bekerja di JSP tanpa pustaka eksternal sehingga Anda dapat meletakkannya hampir di mana saja di server Anda:
Maka Anda hanya melakukan sesuatu seperti:
sumber