Odpowiedzi:
Możesz użyć File#isDirectory()do sprawdzenia, czy podany plik (ścieżka) jest katalogiem. Jeśli tak jest true, po prostu wywołujesz tę samą metodę ponownie z jej File#listFiles()wynikiem. Nazywa się to rekurencją .
Oto podstawowy przykład rozpoczęcia.
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());
}
}
}
Należy zauważyć, że jest to wrażliwe na sytuacje, StackOverflowErrorgdy drzewo jest głębsze niż może pomieścić stos maszyny JVM. Możesz zamiast tego użyć podejścia iteracyjnego lub rekurencji ogonowej , ale to inny temat;)
NullPointerExceptiongdy system plików zmienia się między wywołaniem isDirectoryi listFilesco może się zdarzyć, jeśli System.out.printlnblokuje się lub po prostu masz pecha. Sprawdzanie, czy wartość wyjściowa funkcji listFilesnie jest zerowa, rozwiązałoby ten warunek wyścigu.
java.nio.file.DirectoryStreampozwala na iterację w katalogu i może zostać zaimplementowana w celu uzyskania niewielkiej ilości pamięci, ale jedynym sposobem na upewnienie się byłoby do monitorowania wykorzystania pamięci na określonej platformie.
Jeśli używasz Java 1.7, możesz użyć java.nio.file.Files.walkFileTree(...).
Na przykład:
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();
}
}
}
Jeśli korzystasz z języka Java 8, możesz używać interfejsu strumieniowego z 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();
}
}
}
Sprawdź klasę FileUtils w Apache Commons - w szczególności iteruj pliki :
Umożliwia iterację po plikach w podanym katalogu (i opcjonalnie w jego podkatalogach).
W przypadku Java 7+ jest również https://docs.oracle.com/javase/7/docs/api/java/nio/file/DirectoryStream.html
Przykład zaczerpnięty z 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;
}
To drzewo, więc rekurencja jest twoim przyjacielem: zacznij od katalogu nadrzędnego i wywołaj metodę, aby uzyskać tablicę plików potomnych. Wykonaj iterację przez tablicę potomną. Jeśli bieżąca wartość jest katalogiem, przekaż go do rekurencyjnego wywołania metody. Jeśli nie, odpowiednio przetwórz plik-liść.
Jak wspomniano, jest to problem rekursji. W szczególności warto się przyjrzeć
listFiles()
W java File API tutaj . Zwraca tablicę wszystkich plików w katalogu. Używanie tego wraz z
isDirectory()
sprawdzenie, czy musisz powtórzyć dalej, to dobry początek.
Aby dodać odpowiedź @msandiford, ponieważ w większości przypadków, gdy chodzi się po drzewie plików, możesz chcieć wykonać funkcję jako katalog lub jakikolwiek określony plik jest odwiedzany. Jeśli niechętnie korzystasz ze strumieni. Można zaimplementować następujące metody
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;
}
});
Możesz także nadużywać File.list (FilenameFilter) (i wariantów) do przechodzenia po plikach. Krótki kod i działa we wczesnych wersjach Java, np .:
// 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;
}
});