2010-07-01 4 views

Répondre

166

Vous pouvez utiliser File#isDirectory() pour tester si le fichier (chemin) donné est un répertoire. Si c'est true, alors vous appelez simplement la même méthode avec son résultat File#listFiles(). Ceci est appelé recursion.

Voici un exemple de coup d'envoi 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 ceci est sensible à StackOverflowError lorsque l'arbre est plus profond que la pile de la machine virtuelle Java peut contenir. Vous pouvez utiliser une approche itérative ou tail-recursion à la place, mais c'est un autre sujet;)

+0

remercie Balus, une idée sur quelle profondeur cela peut être comme une conjecture générale? – James

+9

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 tel répertoire, n'utilisez pas la récursivité. –

+3

Ceci est susceptible d'une exception 'NullPointerException' quand le système de fichiers change entre l'appel à' isDirectory' et 'listFiles', ce qui pourrait arriver si' System.out.println' se bloque ou si vous êtes vraiment malchanceux. Vérifier que la sortie de 'listFiles' n'est pas nulle résoudrait cette condition de concurrence. –

1

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. Itérer à travers le tableau enfant. Si la valeur actuelle est un répertoire, passez-la à un appel récursif de votre méthode. Si ce n'est pas le cas, traitez le fichier feuille de manière appropriée.

25

Vérifiez la classe FileUtils dans Apache Commons - spécifiquement iterateFiles:

Permet d'itérer sur les fichiers dans le répertoire donné (et éventuellement ses sous-répertoires).

+4

Cette API ne diffuse vraiment (si vous vous souciez mem usage), il d'abord générer une collection, alors seulement retourne un itérateur dessus: ListFiles de retour (répertoire, Filefilter , dirFilter) .iterator(); –

+0

Bonne option pour Java 1.6. –

1

Comme indiqué, il s'agit d'un problème de récurrence. vous pouvez en particulier, veulent regarder

listFiles() 

Dans l'API File java here. Il retourne un tableau de tous les fichiers dans un répertoire. L'utilisation de ceci avec

isDirectory() 

pour voir si vous avez besoin de recurse est un bon début.

+0

Lien cassé ... !!! –

+0

Ce [link] (https://docs.oracle.com/javase/8/docs/api/java/io/File.html) peut être utile puisque celui de la réponse est cassé. – Donglecow

65

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

} 
+0

est-il un moyen avec les flux pour mettre un point de contrôle quand un nouveau répertoire est parcouru et exécuter une fonction? –

5

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 veut pas de fichiers de sous-répertoires.

6

Pour Java 7+, il y a aussi https://docs.oracle.com/javase/7/docs/api/java/nio/file/DirectoryStream.html

Exemple tiré de la 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; 
} 
0

Pour ajouter avec la réponse @msandiford, comme la plupart du temps quand un arbre fichier u est peut marchèrent vouloir exécuter une fonction en tant que répertoire ou tout fichier particulier est visité. Si vous êtes réticent à utiliser des flux.Les méthodes suivantes surchargées peuvent être mises en œuvre

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