Рекурсивно вывести список всех файлов в каталоге с помощью nio.file.DirectoryStream;
72019 просмотра
8 ответа
Я хочу перечислить все файлы в указанном каталоге и подкаталогах в этом каталоге. Каталоги не должны быть перечислены.
Мой текущий код ниже. Он не работает должным образом, так как перечисляет только файлы и каталоги в указанном каталоге.
Как я могу это исправить?
final List<Path> files = new ArrayList<>();
Path path = Paths.get("C:\\Users\\Danny\\Documents\\workspace\\Test\\bin\\SomeFiles");
try
{
DirectoryStream<Path> stream;
stream = Files.newDirectoryStream(path);
for (Path entry : stream)
{
files.add(entry);
}
stream.close();
}
catch (IOException e)
{
e.printStackTrace();
}
for (Path entry: files)
{
System.out.println(entry.toString());
}
Автор: Danny Rancher
Источник
Размещён: 12.11.2019 09:25
Ответы (8)
63 плюса
Java 8 предоставляет хороший способ для этого:
Files.walk(path)
Этот метод возвращает Stream<Path>
.
31 плюса
Создайте метод, который будет вызывать себя, если следующий элемент является каталогом
void listFiles(Path path) throws IOException {
try (DirectoryStream<Path> stream = Files.newDirectoryStream(path)) {
for (Path entry : stream) {
if (Files.isDirectory(entry)) {
listFiles(entry);
}
files.add(entry);
}
}
}
Автор: Evgeniy Dorofeev
Размещён: 08.01.2014 04:56
26 плюса
Проверьте FileVisitor , очень аккуратно.
Path path= Paths.get("C:\\Users\\Danny\\Documents\\workspace\\Test\\bin\\SomeFiles");
final List<Path> files=new ArrayList<>();
try {
Files.walkFileTree(path, new SimpleFileVisitor<Path>(){
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
if(!attrs.isDirectory()){
files.add(file);
}
return FileVisitResult.CONTINUE;
}
});
} catch (IOException e) {
e.printStackTrace();
}
Автор: Adi
Размещён: 08.01.2014 05:05
6 плюса
Если вы хотите избежать рекурсивного вызова функции и иметь список файлов, который является переменной-членом, вы можете использовать стек:
private List<Path> listFiles(Path path) throws IOException {
Deque<Path> stack = new ArrayDeque<Path>();
final List<Path> files = new LinkedList<>();
stack.push(path);
while (!stack.isEmpty()) {
DirectoryStream<Path> stream = Files.newDirectoryStream(stack.pop());
for (Path entry : stream) {
if (Files.isDirectory(entry)) {
stack.push(entry);
}
else {
files.add(entry);
}
}
stream.close();
}
return files;
}
Автор: Duarte Meneses
Размещён: 07.05.2014 01:34
2 плюса
Используя Rx Java, требование может быть решено несколькими способами, в то же время придерживаясь использования DirectoryStream из JDK.
Следующие комбинации дадут вам желаемый эффект, я бы объяснил их по порядку:
Подход 1 . Рекурсивный подход с использованием операторов flatMap () и defer ()
Подход 2 . Рекурсивный подход с использованием операторов flatMap () и fromCallable
Примечание. Если вы замените использование flatMap () на concatMap () , навигация по дереву каталогов обязательно произойдет в режиме поиска в глубину (DFS). При использовании flatMap () эффект DFS не гарантируется.
Подход 1: Использование flatMap () и defer ()
private Observable<Path> recursiveFileSystemNavigation_Using_Defer(Path dir) {
return Observable.<Path>defer(() -> {
//
// try-resource block
//
try(DirectoryStream<Path> children = Files.newDirectoryStream(dir))
{
//This intermediate storage is required because DirectoryStream can't be navigated more than once.
List<Path> subfolders = Observable.<Path>fromIterable(children)
.toList()
.blockingGet();
return Observable.<Path>fromIterable(subfolders)
/* Line X */ .flatMap(p -> !isFolder(p) ? Observable.<Path> just(p) : recursiveFileSystemNavigation_Using_Defer(p), Runtime.getRuntime().availableProcessors());
// /* Line Y */ .concatMap(p -> !isFolder(p) ? Observable.<Path> just(p) : recursiveFileSystemNavigation_Using_Defer(p));
} catch (IOException e) {
/*
This catch block is required even though DirectoryStream is Closeable
resource. Reason is that .close() call on a DirectoryStream throws a
checked exception.
*/
return Observable.<Path>empty();
}
});
}
Этот подход находит детей заданного каталога, а затем отправляет детей в виде наблюдаемых. Если дочерний файл является файлом, он будет сразу же доступен подписчику, иначе flatMap () в строке X будет вызывать метод, рекурсивно передавая каждый подкаталог в качестве аргумента. Для каждого такого подкаталога flatmap будет внутренне подписываться на своих детей одновременно. Это похоже на цепную реакцию, которую нужно контролировать.
Поэтому использование Runtime.getRuntime (). AvailableProcessors () устанавливает максимальный уровень параллелизма для flatmap () и предотвращает одновременную подписку на все подпапки. Не задавая уровень параллелизма, представьте, что произойдет, если в папке будет 1000 дочерних элементов.
Использование defer () предотвращает преждевременное создание DirectoryStream и гарантирует, что оно произойдет только тогда, когда будет создана настоящая подписка для поиска его подпапок.
Наконец, метод возвращает Observable
//
// Using the defer() based approach
//
recursiveDirNavigation.recursiveFileSystemNavigation_Using_Defer(startingDir)
.subscribeOn(Schedulers.io())
.observeOn(Schedulers.from(Executors.newFixedThreadPool(1)))
.subscribe(p -> System.out.println(p.toUri()));
Недостаток использования defer () состоит в том, что он не справляется с проверенными исключениями, если его функция аргумента генерирует проверенное исключение. Поэтому, хотя DirectoryStream (который реализует Closeable) был создан в блоке try-resource, нам все равно пришлось перехватить IOException, поскольку автоматическое закрытие DirectoryStream генерирует это проверенное исключение.
При использовании стиля на основе Rx использование блоков catch () для обработки ошибок звучит немного странно, потому что четные ошибки отправляются как события в реактивном программировании. Так почему бы нам не использовать оператор, который выставляет такие ошибки как события.
Лучшая альтернатива названа fromCallable () была добавлена в Rx Java 2.x . Второй подход показывает использование этого.
Подход 2. Использование операторов flatMap () и fromCallable
Этот подход использует оператор fromCallable (), который принимает Callable в качестве аргумента. Так как мы хотим рекурсивный подход, ожидаемый результат от этого вызываемого объекта - Observable дочерних элементов данной папки. Поскольку мы хотим, чтобы подписчик получал результаты, когда они доступны, нам необходимо вернуть Observable из этого метода. Так как результат внутреннего вызова - это наблюдаемый список детей, чистый эффект - это наблюдаемая из наблюдаемых.
private Observable<Observable<Path>> recursiveFileSystemNavigation_WithoutExplicitCatchBlock_UsingFromCallable(Path dir) {
/*
* fromCallable() takes a Callable argument. In this case the callbale's return value itself is
* a list of sub-paths therefore the overall return value of this method is Observable<Observable<Path>>
*
* While subscribing the final results, we'd flatten this return value.
*
* Benefit of using fromCallable() is that it elegantly catches the checked exceptions thrown
* during the callable's call and exposes that via onError() operator chain if you need.
*
* Defer() operator does not give that flexibility and you have to explicitly catch and handle appropriately.
*/
return Observable.<Observable<Path>> fromCallable(() -> traverse(dir))
.onErrorReturnItem(Observable.<Path>empty());
}
private Observable<Path> traverse(Path dir) throws IOException {
//
// try-resource block
//
try(DirectoryStream<Path> children = Files.newDirectoryStream(dir))
{
//This intermediate storage is required because DirectoryStream can't be navigated more than once.
List<Path> subfolders = Observable.<Path>fromIterable(children)
.toList()
.blockingGet();
return Observable.<Path>fromIterable(subfolders)
/* Line X */ .flatMap(p -> ( !isFolder(p) ? Observable.<Path> just(p) : recursiveFileSystemNavigation_WithoutExplicitCatchBlock_UsingFromCallable(p).blockingSingle())
,Runtime.getRuntime().availableProcessors());
// /* Line Y */ .concatMap(p -> ( !isFolder(p) ? Observable.<Path> just(p) : recursiveFileSystemNavigation_WithoutExplicitCatchBlock_UsingFromCallable(p).blockingSingle() ));
}
}
После этого подписчик должен будет сгладить поток результатов, как показано ниже:
//
// Using the fromCallable() based approach
//
recursiveDirNavigation.recursiveFileSystemNavigation_WithoutExplicitCatchBlock_UsingFromCallable(startingDir)
.subscribeOn(Schedulers.io())
.flatMap(p -> p)
.observeOn(Schedulers.from(Executors.newFixedThreadPool(1)))
.subscribe(filePath -> System.out.println(filePath.toUri()));
В методе traverse () почему строка X использует блокировку Get
Поскольку рекурсивная функция возвращает Observable
Строка Y в обоих подходах использует concatMap ()
Потому что concatMap () можно удобно использовать, если мы не хотим параллелизма во внутренних подписках, сделанных flatmap ().
В обоих подходах реализация метода isFolder выглядит следующим образом:
private boolean isFolder(Path p){
if(p.toFile().isFile()){
return false;
}
return true;
}
Maven координаты для Java RX 2.0
<dependency>
<groupId>io.reactivex.rxjava2</groupId>
<artifactId>rxjava</artifactId>
<version>2.0.3</version>
</dependency>
Импорт в файл Java
import java.io.IOException;
import java.nio.file.DirectoryStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.concurrent.Executors;
import io.reactivex.Observable;
import io.reactivex.schedulers.Schedulers;
Автор: NitinS
Размещён: 21.12.2016 08:06
2 плюса
Это самая короткая реализация, которую я придумал:
final List<Path> files = new ArrayList<>();
Path path = Paths.get("C:\\Users\\Danny\\Documents\\workspace\\Test\\bin\\SomeFiles");
try {
Files.walk(path).forEach(entry -> list.add(entry));
} catch (IOException e) {
e.printStackTrack();
}
Автор: REjsmont
Размещён: 25.04.2018 08:02
0 плюса
Попробуйте это .. он проходит через каждую папку и распечатывает обе папки, а также файлы: -
public static void traverseDir(Path path) {
try (DirectoryStream<Path> stream = Files.newDirectoryStream(path)) {
for (Path entry : stream) {
if (Files.isDirectory(entry)) {
System.out.println("Sub-Folder Name : " + entry.toString());
traverseDir(entry);
} else {
System.out.println("\tFile Name : " + entry.toString());
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
Автор: Yogesh Deshmukh
Размещён: 09.02.2017 08:08
-1 плюса
Попробуйте: вы получите список каталогов и путь к подкаталогу; Там может быть неограниченный подкаталог, попробуйте использовать recursive
процесс.
public class DriectoryFileFilter {
private List<String> filePathList = new ArrayList<String>();
public List<String> read(File file) {
if (file.isFile()) {
filePathList.add(file.getAbsolutePath());
} else if (file.isDirectory()) {
File[] listOfFiles = file.listFiles();
if (listOfFiles != null) {
for (int i = 0; i < listOfFiles.length; i++){
read(listOfFiles[i]);
}
} else {
System.out.println("[ACCESS DENIED]");
}
}
return filePathList;
}
}
Автор: Zaw Than oo
Размещён: 08.01.2014 05:44
Вопросы из категории :
- java В чем разница между int и Integer в Java и C #?
- java Как я могу определить IP моего маршрутизатора / шлюза в Java?
- java Каков наилучший способ проверки XML-файла по сравнению с XSD-файлом?
- java Как округлить результат целочисленного деления?
- java Преобразование списка <Integer> в список <String>
- file Как получить список каталогов в C?
- file Динамически загружать файл JavaScript
- file Find number of files with a specific extension, in all subdirectories
- file Поиск и замена строки в файле в Python
- file Как я могу получить путь и имя файла, который выполняется в настоящее время?
- nio когда я использую nio, serverSocket.accept () выбрасывает IllegalBlockingModeException
- nio Получает байтовый массив из ByteBuffer в Java
- nio Java NIO: Что такое IOException: Сломанная труба означает?
- nio Java: преобразование строки в и из ByteBuffer и связанных с ней проблем
- nio Рекурсивно перечислять файлы в Java
- directorystream Рекурсивно вывести список всех файлов в каталоге с помощью nio.file.DirectoryStream;
- directorystream Java FileVisitor visit ordered in a directory
- directorystream How to calculate number of documents per hour depending on their "last modified"