Risposte:
È possibile utilizzare File#isDirectory()per verificare se il file (percorso) specificato è una directory. In questo caso true, basta chiamare nuovamente lo stesso metodo con il relativo File#listFiles()risultato. Questo si chiama ricorsione .
Ecco un esempio di kickoff di base.
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());
}
}
}
Si noti che questo è sensibile a StackOverflowErrorquando l'albero è più profondo di quanto lo stack della JVM possa contenere. Potresti voler usare un approccio iterativo o ricorsività della coda , ma questo è un altro argomento;)
NullPointerExceptionquando il file system cambia tra la chiamata a isDirectorye listFilescome potrebbe accadere se i System.out.printlnblocchi o sei davvero sfortunato. Controllare che l'output di listFilesnon sia null risolverebbe tale condizione di competizione.
java.nio.file.DirectoryStreamè possibile eseguire l'iterazione su una directory e potrebbe essere implementato per avere un footprint di memoria ridotto, ma l'unico modo per dirlo sarebbe per monitorare l'utilizzo della memoria su una particolare piattaforma.
Se si utilizza Java 1.7, è possibile utilizzare java.nio.file.Files.walkFileTree(...) .
Per esempio:
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();
}
}
}
Se si utilizza Java 8, è possibile utilizzare l'interfaccia di flusso con 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();
}
}
}
Dai un'occhiata alla classe FileUtils in Apache Commons, in particolare iterateFiles :
Consente l'iterazione sui file nella directory specificata (e facoltativamente nelle sue sottodirectory).
Per Java 7+, esiste anche https://docs.oracle.com/javase/7/docs/api/java/nio/file/DirectoryStream.html
Esempio tratto da 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;
}
È un albero, quindi la ricorsione è il tuo amico: inizia con la directory principale e chiama il metodo per ottenere una matrice di file figlio. Scorrere l'array figlio. Se il valore corrente è una directory, passalo a una chiamata ricorsiva del tuo metodo. In caso contrario, elaborare il file foglia in modo appropriato.
Come notato, questo è un problema di ricorsione. In particolare, potresti voler guardare
listFiles()
Nell'API File Java qui . Restituisce un array di tutti i file in una directory. Usando questo insieme a
isDirectory()
vedere se è necessario ricorrere ulteriormente è un buon inizio.
Per aggiungere con la risposta @msandiford, poiché la maggior parte delle volte quando si cammina su un albero di file, è possibile che si desideri eseguire una funzione come directory o qualsiasi file particolare viene visitato. Se sei riluttante a usare i flussi. È possibile implementare i seguenti metodi sovrascritti
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;
}
});
È inoltre possibile utilizzare impropriamente File.list (FilenameFilter) (e varianti) per l'attraversamento dei file. Codice funzione e funziona nelle prime versioni di Java, ad esempio:
// 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;
}
});