Comment parcourir les fichiers d'un répertoire Java?

175

J'ai besoin d'obtenir une liste de tous les fichiers dans un répertoire, y compris les fichiers dans tous les sous-répertoires. Quelle est la méthode standard pour effectuer une itération de répertoire avec Java?

James
la source

Réponses:

207

Vous pouvez utiliser File#isDirectory()pour tester si le fichier (chemin) donné est un répertoire. Si tel est le cas true, il vous suffit d'appeler à nouveau la même méthode avec son File#listFiles()résultat. C'est ce qu'on appelle la récursivité .

Voici un exemple de lancement de 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());
        }
    }
}

Notez que cela est sensible au StackOverflowErrormoment où l'arborescence est plus profonde que ce que la pile de la JVM peut contenir. Vous voudrez peut-être utiliser une approche itérative ou une récursion de queue à la place, mais c'est un autre sujet;)

BalusC
la source
merci Balus, une idée de la profondeur que cela peut avoir en général?
James
10
Dépend des paramètres de mémoire de votre JVM. Mais généralement quelque chose comme quelques milliers. Si vous pensez que vous pourriez jamais rencontrer un répertoire comme celui-là, n'utilisez pas la récursivité.
Mike Baranczak
4
Cela est susceptible de se NullPointerExceptionproduire lorsque le système de fichiers change entre l'appel à isDirectoryet listFilescomme cela peut arriver si vous System.out.printlnbloquez ou si vous êtes vraiment malchanceux. Vérifier que la sortie de listFilesn'est pas nulle résoudrait cette condition de concurrence.
Mike Samuel
1
@BoratSagdiyev, n'utilisant pas les anciennes API de fichier Java, mais si vous êtes sur une JVM moderne, le java.nio.file.DirectoryStreamvous permet d'itérer sur un répertoire et pourrait être implémenté pour avoir une petite empreinte mémoire, mais le seul moyen de le savoir avec certitude serait pour surveiller l'utilisation de la mémoire sur une plate-forme particulière.
Mike Samuel
1
Le dossier "C: \\" n'est pas le meilleur choix d'un exemple)
Vyacheslav
86

Si vous utilisez Java 1.7, vous pouvez utiliser java.nio.file.Files.walkFileTree(...) .

Par exemple:

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 vous utilisez Java 8, vous pouvez utiliser l'interface de flux avec 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();
    }
  }

}
clstrfsck
la source
1
y a-t-il un moyen avec les flux de mettre un point de contrôle lorsqu'un nouveau répertoire est parcouru et d'exécuter une fonction?
Raghu DV
28

Découvrez la classe FileUtils dans Apache Commons - en particulier iterateFiles :

Permet l'itération sur les fichiers dans un répertoire donné (et éventuellement ses sous-répertoires).

Ben J
la source
5
Cette API n'est pas vraiment en streaming (si vous vous souciez de l'utilisation de mem), elle génère d'abord une collection, puis retourne un itérateur dessus: return listFiles (directory, fileFilter, dirFilter) .iterator ();
Gili Nachum
Bonne option pour Java 1.6.
David I.
D'accord avec @GiliNachum. FileUtils d'Apache collecte d'abord tous les fichiers et leur donne un itérateur. Cela nuit aux ressources si vous avez une énorme quantité de fichiers.
Bogdan Samondros
8

Pour Java 7+, il existe également https://docs.oracle.com/javase/7/docs/api/java/nio/file/DirectoryStream.html

Exemple tiré du 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;
}
Wim Deblauwe
la source
8

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

Utilisez false si vous ne voulez pas de fichiers provenant de sous-répertoires.

fjkjava
la source
3

C'est un arbre, donc la récursivité est votre ami: commencez par le répertoire parent et appelez la méthode pour obtenir un tableau de fichiers enfants. Parcourez le tableau enfant. Si la valeur actuelle est un répertoire, passez-le à un appel récursif de votre méthode. Sinon, traitez le fichier feuille de manière appropriée.

duffymo
la source
2

Comme indiqué, il s'agit d'un problème de récursivité. En particulier, vous voudrez peut-être regarder

listFiles() 

Dans l'API de fichier java ici . Il renvoie un tableau de tous les fichiers d'un répertoire. Utiliser ceci avec

isDirectory()

voir si vous avez besoin de récidiver davantage est un bon début.

Chimmy
la source
Ce lien peut être utile car celui de la réponse est rompu.
Donglecow
0

Pour ajouter avec la réponse @msandiford, comme la plupart du temps quand une arborescence de fichiers est parcourue, vous voudrez peut-être exécuter une fonction en tant que répertoire ou tout fichier particulier est visité. Si vous êtes réticent à utiliser les flux. Les méthodes suivantes remplacées peuvent être implémentées

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;
        }
});
Raghu DV
la source
0

Vous pouvez également abuser de File.list (FilenameFilter) (et de ses variantes) pour la traversée de fichiers. Code court et fonctionne dans les premières versions de Java, par exemple:

// 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;
    }
});
Rob Klinkhamer
la source