¿Cómo itero a través de los archivos en un directorio en Java?


175

Necesito obtener una lista de todos los archivos en un directorio, incluidos los archivos en todos los subdirectorios. ¿Cuál es la forma estándar de lograr la iteración de directorio con Java?

Respuestas:


207

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;)


gracias Balus, ¿alguna idea de cuán profundo puede ser eso como una suposición general?
— James

10
Depende de la configuración de memoria de su JVM. Pero generalmente algo así como unos pocos miles. Si cree que alguna vez podría encontrarse con un directorio como ese, entonces no use la recursividad.
— Mike Baranczak 01 de

44
Esto es susceptible a 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.
— Mike Samuel

1
@BoratSagdiyev, no utiliza las API de archivos Java anteriores, pero si está en una JVM moderna, entonces le 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.
— Mike Samuel

1
La carpeta "C: \\" no es la mejor opción de un ejemplo)
— Vyacheslav

86

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();
    }
  }

}

1
¿Hay alguna manera con las corrientes para poner un punto de control cuando se recorre un nuevo directorio y ejecuta una función?
— Raghu DV

28

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).


55
Esta API no es realmente streaming (si te importa el uso de mem), primero genera una colección, solo luego devuelve un iterador sobre ella: return listFiles (directorio, fileFilter, dirFilter) .iterator ();
— Gili Nachum

Buena opción para Java 1.6.
— David I.

De acuerdo con @GiliNachum. FileUtils de Apache primero recopila todos los archivos y les proporciona un iterador. Es perjudicial para los recursos si tiene una gran cantidad de archivos.
— Bogdan Samondros

8

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;
}

8

Utilizando org.apache.commons.io.FileUtils

File file = new File("F:/Lines");       
Collection<File> files = FileUtils.listFiles(file, null, true);     
for(File file2 : files){
    System.out.println(file2.getName());            
} 

Use false si no desea archivos de subdirectorios.


3

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.


2

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.


Este enlace puede ser útil ya que el que está en la respuesta está roto.
— Donglecow

0

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;
        }
});

0

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;
    }
});
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.