Обход дерева каталогов
Для обхода дерева каталогов существует метод Files.walkFileTree() , содержащий необходимый функционал.
Метод walkFileTree() принимает экземпляр Path и FileVisitor в качестве параметров. Экземпляр Path указывает на каталог, который мы хотим пройти. FileVisitor вызывается во время обхода.
Прежде чем мы рассмотрим, как работает обход, сначала взглянем на интерфейс FileVisitor :
public interface FileVisitor < public FileVisitResult preVisitDirectory( Path dir, BasicFileAttributes attrs) throws IOException; public FileVisitResult visitFile( Path file, BasicFileAttributes attrs) throws IOException; public FileVisitResult visitFileFailed( Path file, IOException exc) throws IOException; public FileVisitResult postVisitDirectory( Path dir, IOException exc) throws IOException; >
Мы должны реализовать интерфейс FileVisitor самостоятельно и передать экземпляр своей реализации методу walkFileTree() . Каждый метод нашей реализации FileVisitor будет вызываться в разное время во время обхода каталога. Если нам не нужно подключаться ко всем этим методам, мы можем расширить класс SimpleFileVisitor , который содержит реализации по умолчанию всех методов в интерфейсе FileVisitor .
Files.walkFileTree(path, new FileVisitor() < @Override public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException < System.out.println("pre visit dir:" + dir); return FileVisitResult.CONTINUE; > @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException < System.out.println("visit file: " + file); return FileVisitResult.CONTINUE; > @Override public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException < System.out.println("visit file failed: " + file); return FileVisitResult.CONTINUE; > @Override public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException < System.out.println("post visit directory: " + dir); return FileVisitResult.CONTINUE; > >);
Каждый из методов в реализации FileVisitor вызывается в разное время во время обхода:
- preVisitDirectory() — непосредственно перед посещением любого каталога
- postVisitDirectory() — сразу после посещения каталога
- visitFile() — для каждого файла, который был посещен во время обхода файла. Он не вызывается для каталогов — только для файлов
- visitFileFailed() — в случае сбоя при посещении файла. Например, если у нас нет необходимых прав доступа или что-то еще идет не так
Каждый из четырех методов возвращает экземпляр перечисления FileVisitResult . Перечисление FileVisitResult содержит следующие четыре параметра (возвращая одно из этих значений, вызываемый метод может решить, как следует продолжить просмотр файла):
- CONTINUE означает, что просмотр файла должен продолжаться как обычно
- TERMINATE означает, что обход файла должен завершиться сейчас
- SKIP_SIBLINGS означает, что обход файла должен продолжаться, но без посещения каких-либо братьев этого файла или каталога
- SKIP_SUBTREE означает, что просмотр файла должен продолжаться, но без посещения записей в этом каталоге. Это значение будет работать, только если оно было возвращено из preVisitDirectory() . Если его вернуть из любых других методов, оно будет интерпретировано как CONTINUE
results matching » «
No results matching » «
Источник
Java обход дерева файлов
Чтобы обойти дерево файла, Вы сначала должны реализовать a FileVisitor . A FileVisitor определяет необходимое поведение в ключевых пунктах в процессе обхода: когда файл посещают, прежде, чем к каталогу получают доступ, после того, как к каталогу получают доступ, или когда отказ происходит. У интерфейса есть четыре метода, которые соответствуют этим ситуациям:
- preVisitDirectory – Вызванный прежде, чем записи каталога посещают.
- postVisitDirectory – Вызванный после того, как все записи в каталоге посещают. Если с какими-либо ошибками встречаются, определенное исключение передают к методу.
- visitFile – Вызванный на файл, который посещают. Файл BasicFileAttributes передается к методу, или можно использовать пакет атрибутов файла, чтобы считать определенный набор атрибутов. Например, можно хотеть читать файл DosFileAttributeView определить, есть ли у файла «скрытый» набор битов.
- visitFileFailed – Вызванный, когда к файлу нельзя получить доступ. Определенное исключение передают к методу. Можно выбрать, выдать ли исключение, напечатать это к консоли или файлу журнала и так далее.
Если Вы не должны реализовать все четыре из FileVisitor методы, вместо того, чтобы реализовать FileVisitor интерфейс, можно расшириться SimpleFileVisitor class. Этот class, который реализует FileVisitor интерфейс, посещает все файлы в дереве и бросает IOError когда с ошибкой встречаются. Можно расширить этот class и переопределить только методы, которых Вы требуете.
Вот пример, который расширяется SimpleFileVisitor напечатать все записи в дереве файла. Это печатает запись, является ли запись регулярным файлом, символьной ссылкой, каталогом, или некоторым другим «неуказанным» типом файла. Это также печатает размер, в байтах, каждого файла. Любое исключение, с которым встречаются, печатается к консоли.
FileVisitor методы показывают полужирным:
import static java.nio.file.FileVisitResult.*; public static class PrintFiles extends SimpleFileVisitor < // Print information about // each type of file. @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attr) < if (attr.isSymbolicLink()) < System.out.format("Symbolic link: %s ", file); >else if (attr.isRegularFile()) < System.out.format("Regular file: %s ", file); >else < System.out.format("Other: %s ", file); >System.out.println("(" + attr.size() + "bytes)"); return CONTINUE; > // Print each directory visited. @Override public FileVisitResult postVisitDirectory(Path dir, IOException exc) < System.out.format("Directory: %s%n", dir); return CONTINUE; >// If there is some error accessing // the file, let the user know. // If you don't override this method // and an error occurs, an IOException // is thrown. @Override public FileVisitResult visitFileFailed(Path file, IOException exc) < System.err.println(exc); return CONTINUE; >>
Заведение ножным стартером Процесса
Как только Вы реализовали Ваш FileVisitor , как Вы инициируете обход файла? Есть два walkFileTree методы в Files class.
Первый метод требует только начальной точки и экземпляра Вашего FileVisitor . Можно вызвать PrintFiles посетитель файла следующим образом:
Path startingDir = . ; PrintFiles pf = new PrintFiles(); Files.walkFileTree(startingDir, pf);
Второе walkFileTree метод позволяет Вам дополнительно определить предел на числе уровней, которые посещают и ряд FileVisitOption перечисления. Если Вы хотите гарантировать, что этот метод обходит все дерево файла, можно определить Integer.MAX_VALUE для максимального параметра глубины.
Можно определить FileVisitOption перечисление, FOLLOW_LINKS , который указывает, что символьные ссылки должны сопровождаться.
Этот фрагмент кода показывает, как метод с четырьмя параметрами может быть вызван:
import static java.nio.file.FileVisitResult.*; Path startingDir = . ; EnumSet opts = EnumSet.of(FOLLOW_LINKS); Finder finder = new Finder(pattern); Files.walkFileTree(startingDir, opts, Integer.MAX_VALUE, finder);
Соображения, Создавая FileVisitor
Дерево файла является обойденной глубиной сначала, но невозможно заставить предположения об итерации упорядочить это, подкаталоги посещают.
Если Ваша программа будет изменять файловую систему, Вы должны тщательно рассмотреть, как Вы реализуете Ваш FileVisitor .
Например, если Вы пишете, что рекурсивное удаляет, Вы сначала удаляете файлы в каталоге прежде, чем удалить каталог непосредственно. В этом случае Вы удаляете каталог в postVisitDirectory .
Если Вы пишете рекурсивную копию, Вы создаете новый каталог в preVisitDirectory прежде, чем попытаться скопировать файлы в это (в visitFiles ). Если Вы хотите сохранить атрибуты исходного каталога (подобный UNIX cp -p команда), Вы должны сделать это после того, как файлы были скопированы, в postVisitDirectory . Copy пример показывает, как сделать это.
Если Вы пишете поиск файла, Вы выполняете сравнение в visitFile метод. Этот метод находит все файлы, которые соответствуют Ваши критерии, но он не находит каталоги. Если Вы хотите найти и файлы и каталоги, следует также выполнить сравнение в любом preVisitDirectory или postVisitDirectory метод. Find пример показывает, как сделать это.
Вы должны решить, хотите ли Вы, чтобы символьные ссылки сопровождались. Если Вы удаляете файлы, например, после символьных ссылок не могло бы быть желательным. Если Вы копируете дерево файла, Вы могли бы хотеть позволить его. По умолчанию, walkFileTree не следует за символьными ссылками.
visitFile метод вызывается для файлов. Если Вы определили FOLLOW_LINKS у опции и Вашего дерева файла есть круговая ссылка к родительскому каталогу, о каталоге цикличного выполнения сообщают в visitFileFailed метод с FileSystemLoopException . Следующий фрагмент кода показывает, как поймать круговую ссылку и от Copy пример:
@Override public FileVisitResult visitFileFailed(Path file, IOException exc) < if (exc instanceof FileSystemLoopException) < System.err.println("cycle detected: " + file); >else < System.err.format("Unable to copy:" + " %s: %s%n", file, exc); >return CONTINUE; >
Этот случай может произойти только, когда программа следует за символьными ссылками.
Управление Потоком
Возможно, Вы хотите обойти поиск дерева файла определенного каталога и, когда найдено, Вы хотите, чтобы процесс завершился. Возможно, Вы хотите пропустить определенные каталоги.
FileVisitor методы возвращают a FileVisitResult значение. Можно прервать процесс обхода файла или управлять, посещают ли каталог значения, которые Вы возвращаете в FileVisitor методы:
- CONTINUE – Указывает, что обход файла должен продолжаться. Если preVisitDirectory возвраты метода CONTINUE , каталог посещают.
- TERMINATE – Сразу прерывает обход файла. Никакие дальнейшие методы обхода файла не вызываются после того, как это значение возвращается.
- SKIP_SUBTREE – Когда preVisitDirectory возвраты это значение, указанный каталог и его подкаталоги пропускаются. Это ответвление «сокращается» дерева.
- SKIP_SIBLINGS – Когда preVisitDirectory возвраты это значение, указанный каталог не посещают, postVisitDirectory не вызывается, и не далее непосещаемые одноуровневые элементы посещают. Если возвращено из postVisitDirectory метод, никакие дальнейшие одноуровневые элементы не посещают. По существу ничто далее не происходит в указанном каталоге.
В этом фрагменте кода называют любой каталог SCCS пропускается:
import static java.nio.file.FileVisitResult.*; public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) < (if (dir.getFileName().toString().equals("SCCS")) < return SKIP_SUBTREE; >return CONTINUE; >
В этом фрагменте кода, как только определенный файл располагается, имя файла печатается к стандартному выводу, и обход файла завершается:
import static java.nio.file.FileVisitResult.*; // The file we are looking for. Path lookingFor = . ; public FileVisitResult visitFile(Path file, BasicFileAttributes attr) < if (file.getFileName().equals(lookingFor)) < System.out.println("Located file: " + file); return TERMINATE; >return CONTINUE; >
Примеры
Следующие примеры демонстрируют механизм обхода файла:
- Find – Рекурсивно вызывает поиск дерева файла файлов и каталогов, которые соответствуют определенный образец шарика. Этот пример обсуждается в Обнаружении Файлов.
- Chmod – Рекурсивно полномочия изменений на дереве файла (для систем POSIX только).
- Copy – Рекурсивно копирует дерево файла.
- WatchDir – Демонстрирует механизм, который наблюдает каталог за файлами, которые были созданы, удалены или изменены. Вызов этой программы с -r опция наблюдает все дерево за изменениями. Для получения дополнительной информации о службе уведомления о файле, см. Наблюдение Каталога для Изменений.
Ваше использование этой страницы и всего материала на страницах под «Учебным баннером» Java подвергается этим официальным уведомлениям.
Авторское право © 1995, 2012 Oracle и/или его филиалы. Все права защищены.
Источник
How do I iterate through the files in a directory and it’s sub-directories in Java?
I need to get a list of all the files in a directory, including files in all the sub-directories. What is the standard way to accomplish directory iteration with Java?
10 Answers 10
You can use File#isDirectory() to test if the given file (path) is a directory. If this is true , then you just call the same method again with its File#listFiles() outcome. This is called recursion.
Here’s a basic kickoff example:
package com.stackoverflow.q3154488; import java.io.File; public class Demo < public static void main(String. args) < File dir = new File("/path/to/dir"); showFiles(dir.listFiles()); >public static void showFiles(File[] files) < for (File file : files) < if (file.isDirectory()) < System.out.println("Directory: " + file.getAbsolutePath()); showFiles(file.listFiles()); // Calls same method again. >else < System.out.println("File: " + file.getAbsolutePath()); >> > >
Note that this is sensitive to StackOverflowError when the tree is deeper than the JVM’s stack can hold. If you’re already on Java 8 or newer, then you’d better use Files#walk() instead which utilizes tail recursion:
package com.stackoverflow.q3154488; import java.io.File; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; public class DemoWithJava8 < public static void main(String. args) throws Exception < Path dir = Paths.get("/path/to/dir"); Files.walk(dir).forEach(path ->showFile(path.toFile())); > public static void showFile(File file) < if (file.isDirectory()) < System.out.println("Directory: " + file.getAbsolutePath()); >else < System.out.println("File: " + file.getAbsolutePath()); >> >
Источник