Respuestas:
Puede usar File#isDirectory()para probar si el archivo (ruta) dado es un directorio. Si es así true, simplemente vuelve a llamar al mismo método con su File#listFiles()resultado. Esto se llama recursividad .
Aquí hay un ejemplo básico de inicio.
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());
}
}
}
Tenga en cuenta que esto es sensible a StackOverflowErrorcuando el árbol es más profundo de lo que puede contener la pila de la JVM. Es posible que desee utilizar un enfoque iterativo o recursión de cola en su lugar, pero ese es otro tema;)
NullPointerExceptioncuando el sistema de archivos cambia entre la llamada isDirectoryy, listFilescomo podría suceder si se System.out.printlnbloquean o simplemente tienes mala suerte. Verificar que la salida de listFilesno sea nula resolvería esa condición de carrera.
java.nio.file.DirectoryStreampermite iterar sobre un directorio, y podría implementarse para tener una pequeña huella de memoria, pero la única forma de saberlo con certeza sería para monitorear el uso de memoria en una plataforma en particular.
Si está utilizando Java 1.7, puede usarlo java.nio.file.Files.walkFileTree(...).
Por ejemplo:
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();
}
}
}
Si está utilizando Java 8, puede usar la interfaz de transmisión 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();
}
}
}
Consulte la clase FileUtils en Apache Commons, específicamente iterateFiles :
Permite la iteración sobre los archivos en un directorio dado (y opcionalmente sus subdirectorios).
Para Java 7+, también hay https://docs.oracle.com/javase/7/docs/api/java/nio/file/DirectoryStream.html
Ejemplo tomado del 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;
}
Es un árbol, así que la recursión es tu amiga: comienza con el directorio principal y llama al método para obtener una matriz de archivos secundarios. Iterar a través de la matriz secundaria. Si el valor actual es un directorio, páselo a una llamada recursiva de su método. De lo contrario, procese el archivo de hoja adecuadamente.
Como se señaló, este es un problema de recurrencia. En particular, es posible que desee mirar
listFiles()
En la API de Java File aquí . Devuelve una matriz de todos los archivos en un directorio. Usando esto junto con
isDirectory()
para ver si necesita repetir aún más es un buen comienzo.
Para agregar con la respuesta @msandiford, como la mayoría de las veces cuando se recorre un árbol de archivos, es posible que desee ejecutar una función como un directorio o se visita cualquier archivo en particular. Si eres reacio a usar corrientes. Se pueden implementar los siguientes métodos anulados
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;
}
});
También puede usar incorrectamente File.list (FilenameFilter) (y variantes) para el recorrido del archivo. Código corto y funciona en versiones tempranas de Java, por ejemplo:
// 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;
}
});