1. Обзор
В этом кратком руководстве мы рассмотрим различные способы перечисления файлов в каталоге .
2. Листинг
Если мы хотим вывести список всех файлов в каталоге и пропустить дальнейшее изучение подкаталогов, мы можем просто использовать java.io.File#listFiles
:
public Set<String> listFilesUsingJavaIO(String dir) {
return Stream.of(new File(dir).listFiles())
.filter(file -> !file.isDirectory())
.map(File::getName)
.collect(Collectors.toSet());
}
3. DirectoryStream
Однако в Java 7 появилась более быстрая альтернатива File #listFiles,
называемая DirectoryStream
.
Давайте посмотрим, как выглядит эквивалент:
public Set<String> listFilesUsingDirectoryStream(String dir) throws IOException {
Set<String> fileList = new HashSet<>();
try (DirectoryStream<Path> stream = Files.newDirectoryStream(Paths.get(dir))) {
for (Path path : stream) {
if (!Files.isDirectory(path)) {
fileList.add(path.getFileName()
.toString());
}
}
}
return fileList;
}
Мы легко видим, что, хотя DirectoryStream
может быть быстрее, он не является частью Stream
API и не совсем подходит для работы с ним.
Кроме того, DirectoryStream
требует, чтобы мы закрыли ресурс, то есть обернули его с помощью try-with-resources
.
4. Листинг в Java 8
Если мы используем Java 8, мы можем извлечь выгоду из нового метода java.nio.file.Files#list .
Он возвращает лениво заполненный поток
записей в каталоге.
Давайте посмотрим на простой пример:
public Set listFilesUsingFilesList(String dir) throws IOException {
try (Stream stream = Files.list(Paths.get(dir))) {
return stream
.filter(file -> !Files.isDirectory(file))
.map(Path::getFileName)
.map(Path::toString)
.collect(Collectors.toSet());
}
}
Если нам требуется своевременная утилизация ресурсов файловой системы, мы должны использовать оператор try-with-resources
. Таким образом, мы гарантируем, что поток будет закрыт сразу после завершения операций с потоком.
5. Ходьба
Или мы можем вывести список всех файлов в каталоге, пройдя
его до настроенной глубины
.
Давайте используем java.nio.file.Files#walk
для вывода списка всех файлов в каталоге на заданную глубину:
public Set<String> listFilesUsingFileWalk(String dir, int depth) throws IOException {
try (Stream<Path> stream = Files.walk(Paths.get(dir), depth)) {
return stream
.filter(file -> !Files.isDirectory(file))
.map(Path::getFileName)
.map(Path::toString)
.collect(Collectors.toSet());
}
}
Конечно, не забудьте использовать try-with-resources
, чтобы дескриптор файла для каталога закрывался
должным образом.
Или, если мы хотим иметь больший контроль над тем, что происходит с каждым посещенным файлом, мы также можем предоставить реализацию посетителя:
public Set<String> listFilesUsingFileWalkAndVisitor(String dir) throws IOException {
Set<String> fileList = new HashSet<>();
Files.walkFileTree(Paths.get(dir), new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
throws IOException {
if (!Files.isDirectory(file)) {
fileList.add(file.getFileName().toString());
}
return FileVisitResult.CONTINUE;
}
});
return fileList;
}
Это удобно, когда мы хотим выполнять дополнительное чтение, перемещение или удаление файлов по ходу работы.
6. Заключение
В этом кратком руководстве мы рассмотрели различные способы отображения файлов в каталоге.
Как всегда, полный исходный код примеров доступен на GitHub .