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.