Come posso scorrere i file in una directory in Java?


175

Ho bisogno di ottenere un elenco di tutti i file in una directory, inclusi i file in tutte le sottodirectory. Qual è il modo standard per eseguire l'iterazione di directory con Java?

Risposte:


207

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


grazie Balus, qualche idea su quanto possa essere profonda un'ipotesi generale?
— James,

10
Dipende dalle impostazioni di memoria della tua JVM. Ma generalmente qualcosa come qualche migliaio. Se pensi di poter mai imbatterti in una directory del genere, non utilizzare la ricorsione.
— Mike Baranczak,

4
Questo è suscettibile a 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.
— Mike Samuel,

1
@BoratSagdiyev, Non utilizzando le vecchie API dei file Java, ma se si utilizza una JVM moderna, 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.
— Mike Samuel,

1
La cartella "C: \\" non è la scelta migliore di un esempio)
— Vyacheslav

86

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

}

1
c'è un modo con gli stream per mettere un checkpoint quando si cammina una nuova directory ed eseguire una funzione?
— Raghu DV,

28

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


5
Questa API non è veramente streaming (se ti interessa l'utilizzo dei mem), prima genera una raccolta, solo poi ci restituisce un iteratore: return listFiles (directory, fileFilter, dirFilter) .iterator ();
— Gili Nachum,

Buona opzione per Java 1.6.
— David I.

Accetto con @GiliNachum. FileUtils di Apache prima raccoglie tutti i file e fornisce loro un iteratore. È dannoso per le risorse se si dispone di un'enorme quantità di file.
— Bogdan Samondros,

8

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

8

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

Utilizzare false se non si desidera file da sottodirectory.


3

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


2

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.


Questo link potrebbe essere utile poiché quello nella risposta è rotto.
— Donglecow,

0

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

0

È 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;
    }
});
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.