Відповіді:
Ви можете використовувати File#isDirectory()для перевірки, чи даний файл (шлях) є каталогом. Якщо це так true, то ви знову викликаєте той самий метод з його File#listFiles()результатом. Це називається рекурсією .
Ось основний приклад старту.
public static void main(String... args) {
File[] files = new File("C:/").listFiles();
showFiles(files);
}
public static void showFiles(File[] files) {
for (File file : files) {
if (file.isDirectory()) {
System.out.println("Directory: " + file.getName());
showFiles(file.listFiles()); // Calls same method again.
} else {
System.out.println("File: " + file.getName());
}
}
}
Зауважте, що це чутливо до того, StackOverflowErrorколи дерево знаходиться глибше, ніж може містити стек JVM. Ви можете скористатися ітеративним підходом або рекурсією хвоста , але це інша тема;)
NullPointerExceptionколи файлова система змінюється між викликом на isDirectoryі listFilesяк це може статися, якщо System.out.printlnблокується або вам просто не пощастить. Перевірка того, що результат listFilesне є нульовим, вирішить цю умову гонки.
java.nio.file.DirectoryStreamви можете переглядати каталог, і він може бути реалізований, щоб мати невеликий слід пам'яті, але єдиним способом сказати точно було б контролювати використання пам'яті на певній платформі.
Якщо ви використовуєте Java 1.7, ви можете використовувати java.nio.file.Files.walkFileTree(...) .
Наприклад:
public class WalkFileTreeExample {
public static void main(String[] args) {
Path p = Paths.get("/usr");
FileVisitor<Path> fv = new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
throws IOException {
System.out.println(file);
return FileVisitResult.CONTINUE;
}
};
try {
Files.walkFileTree(p, fv);
} catch (IOException e) {
e.printStackTrace();
}
}
}
Якщо ви використовуєте Java 8, ви можете використовувати інтерфейс потоку за допомогою java.nio.file.Files.walk(...):
public class WalkFileTreeExample {
public static void main(String[] args) {
try (Stream<Path> paths = Files.walk(Paths.get("/usr"))) {
paths.forEach(System.out::println);
} catch (IOException e) {
e.printStackTrace();
}
}
}
Ознайомтеся з класом FileUtils в Apache Commons - конкретно ітераційними файлами :
Дозволяє ітерацію файлів у вказаному каталозі (та необов'язково його підкаталогах).
Для Java 7+ також є https://docs.oracle.com/javase/7/docs/api/java/nio/file/DirectoryStream.html
Приклад, взятий з Javadoc:
List<Path> listSourceFiles(Path dir) throws IOException {
List<Path> result = new ArrayList<>();
try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir, "*.{c,h,cpp,hpp,java}")) {
for (Path entry: stream) {
result.add(entry);
}
} catch (DirectoryIteratorException ex) {
// I/O error encounted during the iteration, the cause is an IOException
throw ex.getCause();
}
return result;
}
Це дерево, тому рекурсія - ваш друг: почніть з батьківського каталогу та зателефонуйте методу, щоб отримати масив дочірніх файлів. Ітерація через дочірній масив. Якщо поточне значення - це каталог, переведіть його на рекурсивний виклик вашого методу. Якщо ні, обробіть файл листа належним чином.
Як зазначалося, це проблема рекурсії. Зокрема, ви можете поглянути
listFiles()
У Java-файлі API тут . Він повертає масив усіх файлів у каталозі. Використовуючи це разом з
isDirectory()
побачити, чи потрібно повторювати далі - це хороший початок.
Щоб додати відповідь @msandiford, оскільки більшість випадків, коли дерево файлів ходить u, можливо, захочеться виконати функцію у вигляді каталогу або будь-якого конкретного файлу. Якщо ви неохоче використовуєте потоки. Можуть бути реалізовані наступні способи, які перекрито
Files.walkFileTree(Paths.get(Krawl.INDEXPATH), EnumSet.of(FileVisitOption.FOLLOW_LINKS), Integer.MAX_VALUE,
new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs)
throws IOException {
// Do someting before directory visit
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
throws IOException {
// Do something when a file is visited
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult postVisitDirectory(Path dir, IOException exc)
throws IOException {
// Do Something after directory visit
return FileVisitResult.CONTINUE;
}
});
Ви також можете неправильно використовувати File.list (FilenameFilter) (та варіанти) для обходу файлів. Короткий код і працює у ранніх версіях Java, наприклад:
// list files in dir
new File(dir).list(new FilenameFilter() {
public boolean accept(File dir, String name) {
String file = dir.getAbsolutePath() + File.separator + name;
System.out.println(file);
return false;
}
});