
Berikut adalah persyaratannya :
- Mulai dari benda Jalan diberikan, secara rekursif harus melalui setiap direktori untuk mencari file yang cocok dengan pola tertentu.
- Perlu panggilan metode tunggal, sesuatu seperti DirUtils.glob (Jalan jalan, pola String).
- Kami ingin pencarian menjadi asynchronous, sehingga kami dapat iterate atas file saat ditemukan.
Rencana untuk memenuhi tujuan kami adalah lurus ke depan :D :
- Buat objek DirectoryStream.Filter dari pola yang diberikan.
- Gunakan metode Files.walkFileTree untuk secara rekursif mencari file yang cocok dengan pola kita.
- Jalankan pencarian di thread terpisah, dan ketika file yang cocok ditemukan, menempatkannya dalam antrian.
- Iterator DirectoryStream akan menarik file dari antrian saat tersedia
Pengungkapan: Posting ini hanyalah upaya untuk melihat apakah membuat DirectorySteam, asynchronous rekursif akan bekerja, saya membuat ada jaminan tentang kode disajikan di sini, YMMV.
Filter
DirectoryStream memiliki antarmuka statis, Filter, yang digunakan untuk menentukan apakah objek jalan harus diterima. Obyek filter dibangun dengan terlebih dahulu menciptakan objek PathMatcher kemudian menggunakan PathMatcher di Filter itu menerima metode :
Search Rekursifpublic static DirectoryStream.FilterbuildGlobFilter(String pattern) { final PathMatcher pathMatcher = getPathMatcher("glob:"+pattern); return new DirectoryStream.Filter () { @Override public boolean accept(Path entry) throws IOException { return pathMatcher.matches(entry); } }; }
Untuk melakukan pencarian kita akan penggunaan metode Files.walkFileTree dengan benda FunctionVisitor. FunctionVisitor adalah subclass dari SimpleFileVisitor yang membutuhkan Fungsi Guava sebagai argumen konstruktor. Fungsi yang diberikan disebut sebagai setiap file dikunjungi dan diperiksa oleh objek DirectoryStream.Filter untuk pertandingan. Kami membungkus penciptaan obyek Fungsi dalam panggilan metode :
Top 6 Hapus adalah memeriksa untuk pertandingan pada nama file. Jika kecocokan ditemukan, objek jalan ditempatkan dalam LinkedBlockingQueue,, pathsBlockingQueue on line 7. Pada baris 12, kita melihat variabel contoh pathTask, yang merupakan pegangan FutureTask ke thread pencarian. Jika pathTask telah dibatalkan kami mengakhiri pencarian, jika tidak melanjutkan.
private FunctiongetFunction(final Filter filter) { return new Function () { @Override public FileVisitResult apply(Path input) { try { if (filter.accept(input.getFileName())) { pathsBlockingQueue.offer(input); } } catch (IOException e) { throw new RuntimeException(e.getMessage()); } return (pathTask.isCancelled()) ? FileVisitResult.TERMINATE : FileVisitResult.CONTINUE; } }; }
Thread Pencarian
Untuk menjalankan pencarian, kita membungkus metode Files.walkFileTree dalam sebuah objek Callable, yang digunakan sebagai argumen konstruktor untuk pathTask, objek FutureTask. Dengan menggunakan FutureTask, kita memiliki hook ke membatalkan pencarian serta mampu memeriksa status itu berjalan.
Pada baris 5 kita melihat panggilan ke metode getFunction dari contoh sebelumnya. Top 9 awal pemanggilan metode digunakan untuk spin off pencarian di thread sendiri itu:private void findFiles(final Path startPath, final Filter filter) { pathTask = new FutureTask(new Callable () { @Override public Void call() throws Exception { Files.walkFileTree(startPath, new FunctionVisitor(getFunction(filter))); return null; } }); start(pathTask); }
Kami menggunakan objek Thread bukan ExecutorService karena kita hanya perlu sebuah thread tunggal untuk mengeksekusi sekali. Karena kita tidak menyampaikan tugas-tugas berikutnya, ExecutorService sebenarnya tidak diperlukan.
private void start(FutureTaskfutureTask) { new Thread(futureTask).start(); }
Pelaksana DirectoryStream A
Untuk menerapkan sebuah DirectoryStream ada dua metode yang perlu diganti - iterator dan dekat. DirectoryStream memperluas antarmuka AutoCloseable, sehingga bila digunakan dengan percobaan-dengan-sumber konstruk, metode dekat secara otomatis dipanggil, melepaskan sumber daya yang mendasari. Bagian yang paling menarik dari kode ini override metode iterator:
Top 2 kita periksa untuk melihat apakah iterator sebelumnya telah ditutup dan melemparkan UnsupportedOperationException jika itu terjadi. Jalur 3 kicks off benang pencarian seperti yang kita lihat dari contoh sebelumnya. Metode hasNext adalah tempat nyata "otak" dari kelas berada. Sejak pencarian adalah asynchronous DirectoryStream akan mencoba untuk iterate atas file segera, tetapi perlu ada koordinasi dengan beberapa benang pencarian karena menemukan objek jalan pencocokan dan menempatkan mereka ke dalam antrian. On line 9 pertama kita sebut polling (panggilan memblokir non) dan mengatur hasil untuk variabel path didefinisikan pada baris 5. Jika objek adalah null jalan kita drop ke dalam while loop yang memanggil polling lagi, tapi kali ini itu panggilan menghalangi dengan batas waktu 5 milidetik. Kami akan tinggal di loop yang sampai jalur non-null dikembalikan atau benang pencarian telah selesai atau dibatalkan. Pada baris 13 kita memeriksa null untuk menentukan apakah kita memiliki hasil yang valid atau jika ada benda jalan lagi untuk kembali. Jika hasNext kembali benar, metode selanjutnya mengembalikan objek jalan yang diambil oleh panggilan hasNext sebelumnya. Proses ini akan berlanjut sampai semua hasil telah kembali.public Iteratoriterator() { confirmNotClosed(); findFiles(startPath, filter); return new Iterator () { Path path; @Override public boolean hasNext() { try { path = pathsBlockingQueue.poll(); while (!pathTask.isDone() && path == null) { path = pathsBlockingQueue.poll(5, TimeUnit.MILLISECONDS); } return (path != null) ? true : false; } catch (InterruptedException e) { Thread.currentThread().interrupt(); } return false; } @Override public Path next() { return path; } @Override public void remove() { throw new UnsupportedOperationException("Removal not supported"); } }; }
Conclusion
Putting this all together we now have the AsynchronousRecursiveDirectoryStream class. By combining our new class with DirUtils we can iterate over an entire directory tree:try(DirectoryStreamIt is hoped that the reader found this useful. As always, comments and suggestions are welcomed. Thanks for your time.directoryStream = DirUtils.glob(path,"*")){ for(Path path : directoryStream){ .... } }
0 Komentar
Terimakasih telah berkomentar