web-dev-qa-db-fra.com

Lister récursivement les fichiers dans Java

Comment lister récursivement tous les fichiers dans un répertoire Java? Le cadre fournit-il une utilité?

J'ai vu beaucoup d'implémentations de hacky. Mais aucun du cadre ou nio

234
Quintin Par

Java 8 fournit un flux Nice pour traiter tous les fichiers d'une arborescence.

Files.walk(Paths.get(path))
        .filter(Files::isRegularFile)
        .forEach(System.out::println);

Cela fournit un moyen naturel de parcourir les fichiers. Comme il s’agit d’un flux, vous pouvez effectuer toutes les opérations de flux Nice sur le résultat, telles que limite, regroupement, mappage, sortie anticipée, etc.

UPDATE: Je pourrais signaler qu'il existe aussi Files.find qui prend un BiPredicate cela pourrait être plus efficace si vous devez vérifier les attributs de fichier.

Files.find(Paths.get(path),
           Integer.MAX_VALUE,
           (filePath, fileAttr) -> fileAttr.isRegularFile())
        .forEach(System.out::println);

Notez que bien que JavaDoc élude que cette méthode puisse être plus efficace que Files.walk elle est effectivement identique, la différence de performance peut être observée si vous récupérez également des attributs de fichier dans votre filtre. En fin de compte, si vous devez filtrer les attributs, utilisez Files.find , sinon utilisez Files.walk , principalement parce qu'il y a des surcharges et que c'est plus pratique.

TESTS: Comme demandé, j'ai fourni une comparaison des performances de nombreuses réponses. Découvrez le projet Github qui contient les résultats et un cas de test .

285
Brett Ryan

FileUtils a iterateFiles et listFiles méthodes. Donnez-leur un essai. (de commons-io )

Edit: Vous pouvez cochez cette case pour un repère de différentes approches. Il semble que l’approche commons-io soit lente, alors choisissez quelques-unes des plus rapides à partir de là (si cela compte)

158
Bozho

// Prêt à courir

import Java.io.File;

public class Filewalker {

    public void walk( String path ) {

        File root = new File( path );
        File[] list = root.listFiles();

        if (list == null) return;

        for ( File f : list ) {
            if ( f.isDirectory() ) {
                walk( f.getAbsolutePath() );
                System.out.println( "Dir:" + f.getAbsoluteFile() );
            }
            else {
                System.out.println( "File:" + f.getAbsoluteFile() );
            }
        }
    }

    public static void main(String[] args) {
        Filewalker fw = new Filewalker();
        fw.walk("c:\\" );
    }

}
133
stacker

Java 7 aura a Files.walkFileTree :

Si vous fournissez un point de départ et un visiteur de fichier, il invoquera différentes méthodes sur le visiteur de fichier lorsqu'il parcourra le fichier dans l'arborescence de fichiers. Nous nous attendons à ce que les utilisateurs l'utilisent s'ils développent une copie récursive, un déplacement récursif, une suppression récursive ou une opération récursive qui définit des autorisations ou effectue une autre opération sur chacun des fichiers.

Il y a maintenant un entier tutoriel Oracle sur cette question .

66
yawn

Aucune bibliothèque externe nécessaire.
Renvoie une collection afin que vous puissiez en faire ce que vous voulez après l'appel.

public static Collection<File> listFileTree(File dir) {
    Set<File> fileTree = new HashSet<File>();
    if(dir==null||dir.listFiles()==null){
        return fileTree;
    }
    for (File entry : dir.listFiles()) {
        if (entry.isFile()) fileTree.add(entry);
        else fileTree.addAll(listFileTree(entry));
    }
    return fileTree;
}
25
Petrucio

Je voudrais aller avec quelque chose comme:

public void list(File file) {
    System.out.println(file.getName());
    File[] children = file.listFiles();
    for (File child : children) {
        list(child);
    }
}

Le System.out.println est juste là pour indiquer de faire quelque chose avec le fichier. il n'est pas nécessaire de différencier les fichiers des répertoires, puisqu'un fichier normal n'aura tout simplement aucun enfant.

17
Stefan Schmidt

Je préfère utiliser une file d'attente plutôt que la récursivité pour ce type de traversion simple:

List<File> allFiles = new ArrayList<File>();
Queue<File> dirs = new LinkedList<File>();
dirs.add(new File("/start/dir/"));
while (!dirs.isEmpty()) {
  for (File f : dirs.poll().listFiles()) {
    if (f.isDirectory()) {
      dirs.add(f);
    } else if (f.isFile()) {
      allFiles.add(f);
    }
  }
}
13
benroth

écrivez-le vous-même en utilisant une récursivité simple:

public List<File> addFiles(List<File> files, File dir)
{
    if (files == null)
        files = new LinkedList<File>();

    if (!dir.isDirectory())
    {
        files.add(dir);
        return files;
    }

    for (File file : dir.listFiles())
        addFiles(files, file);
    return files;
}
12
pstanton

Avec Java 7, vous pouvez utiliser la classe suivante:

import Java.io.IOException;
import Java.nio.file.FileVisitResult;
import Java.nio.file.Files;
import Java.nio.file.Path;
import Java.nio.file.Paths;
import Java.nio.file.SimpleFileVisitor;
import Java.nio.file.attribute.BasicFileAttributes;

public class MyFileIterator extends SimpleFileVisitor<Path>
{
    public MyFileIterator(String path) throws Exception
    {
        Files.walkFileTree(Paths.get(path), this);
    }

    @Override
    public FileVisitResult visitFile(Path file,
            BasicFileAttributes attributes) throws IOException
    {
        System.out.println("File: " + file);
        return FileVisitResult.CONTINUE;
    }

    @Override
    public FileVisitResult preVisitDirectory(Path dir,
            BasicFileAttributes attributes) throws IOException
    {
        System.out.println("Dir: " + dir);
        return FileVisitResult.CONTINUE;
    }
}
8
chao

Ce code est prêt à fonctionner

public static void main(String... args) {
    File[] files = new File("D:/").listFiles();
    if (files != null) 
       getFiles(files);
}

public static void getFiles(File[] files) {
    for (File file : files) {
        if (file.isDirectory()) {
            getFiles(file.listFiles());
        } else {
            System.out.println("File: " + file);
        }
    }
}
7
Ebraheem Alrabee'

Je pense que cela devrait faire le travail:

File dir = new File(dirname);
String[] files = dir.list();

De cette façon, vous avez des fichiers et des répertoires. Maintenant, utilisez la récursivité et faites de même pour les répertoires (la méthode File a la méthode isDirectory().).

7
Michał Niklas

Dans Java 8, nous pouvons maintenant utiliser l'utilitaire de fichiers pour parcourir une arborescence de fichiers. Très simple.

Files.walk(root.toPath())
      .filter(path -> !Files.isDirectory(path))
      .forEach(path -> System.out.println(path));
5
Roy Kachouh

Outre la traversée récursive, on peut également utiliser une approche basée sur le visiteur.

Le code ci-dessous utilise une approche basée sur les visiteurs pour la traversée. On s'attend à ce que l'entrée du programme soit le répertoire racine à traverser.

public interface Visitor {
    void visit(DirElement d);
    void visit(FileElement f);
}

public abstract class Element {
    protected File rootPath;
    abstract void accept(Visitor v);

    @Override
    public String toString() {
        return rootPath.getAbsolutePath();
    }
}

public class FileElement extends Element {
    FileElement(final String path) {
        rootPath = new File(path);
    }

    @Override
    void accept(final Visitor v) {
        v.visit(this);
    }
}

public class DirElement extends Element implements Iterable<Element> {
    private final List<Element> elemList;
    DirElement(final String path) {
        elemList = new ArrayList<Element>();
        rootPath = new File(path);
        for (File f : rootPath.listFiles()) {
            if (f.isDirectory()) {
                elemList.add(new DirElement(f.getAbsolutePath()));
            } else if (f.isFile()) {
                elemList.add(new FileElement(f.getAbsolutePath()));
            }
        }
    }

    @Override
    void accept(final Visitor v) {
        v.visit(this);
    }

    public Iterator<Element> iterator() {
        return elemList.iterator();
    }
}

public class ElementWalker {
    private final String rootDir;
    ElementWalker(final String dir) {
        rootDir = dir;
    }

    private void traverse() {
        Element d = new DirElement(rootDir);
        d.accept(new Walker());
    }

    public static void main(final String[] args) {
        ElementWalker t = new ElementWalker("C:\\temp");
        t.traverse();
    }

    private class Walker implements Visitor {
        public void visit(final DirElement d) {
            System.out.println(d);
            for(Element e:d) {
                e.accept(this);
            }
        }

        public void visit(final FileElement f) {
            System.out.println(f);
        }
    }
}
4
sateesh

Vous pouvez utiliser le code ci-dessous pour obtenir de manière récursive une liste de fichiers de dossiers ou de répertoires spécifiques.

public static void main(String args[]) {

        recusiveList("D:");

    }

    public static void recursiveList(String path) {

        File f = new File(path);
        File[] fl = f.listFiles();
        for (int i = 0; i < fl.length; i++) {
            if (fl[i].isDirectory() && !fl[i].isHidden()) {
                System.out.println(fl[i].getAbsolutePath());
                recusiveList(fl[i].getAbsolutePath());
            } else {
                System.out.println(fl[i].getName());
            }
        }
    }
3
Rakesh Chaudhari

BFS non récursif avec une liste unique (par exemple, la recherche de fichiers * .eml):

    final FileFilter filter = new FileFilter() {
        @Override
        public boolean accept(File file) {
            return file.isDirectory() || file.getName().endsWith(".eml");
        }
    };

    // BFS recursive search
    List<File> queue = new LinkedList<File>();
    queue.addAll(Arrays.asList(dir.listFiles(filter)));

    for (ListIterator<File> itr = queue.listIterator(); itr.hasNext();) {
        File file = itr.next();
        if (file.isDirectory()) {
            itr.remove();
            for (File f: file.listFiles(filter)) itr.add(f);
        }
    }
1
bobah

Je suis venu avec ceci pour imprimer tous les fichiers/noms de fichiers de manière récursive.

private static void printAllFiles(String filePath,File folder) {
    if(filePath==null) {
        return;
    }
    File[] files = folder.listFiles();
    for(File element : files) {
        if(element.isDirectory()) {
            printAllFiles(filePath,element);
        } else {
            System.out.println(" FileName "+ element.getName());
        }
    }
}
1
kanaparthikiran
    private void fillFilesRecursively(File file, List<File> resultFiles) {
        if (file.isFile()) {
            resultFiles.add(file);
        } else {
            for (File child : file.listFiles()) {
                fillFilesRecursively(child, resultFiles);
            }
        }
    }
1
legendmohe

Ma version (bien sûr j'aurais pu utiliser la promenade intégrée dans Java 8 ;-)):

public static List<File> findFilesIn(File rootDir, Predicate<File> predicate) {
        ArrayList<File> collected = new ArrayList<>();
        walk(rootDir, predicate, collected);
        return collected;
    }

    private static void walk(File dir, Predicate<File> filterFunction, List<File> collected) {
        Stream.of(listOnlyWhenDirectory(dir))
                .forEach(file -> walk(file, filterFunction, addAndReturn(collected, file, filterFunction)));
    }

    private static File[] listOnlyWhenDirectory(File dir) {
        return dir.isDirectory() ? dir.listFiles() : new File[]{};
    }

    private static List<File> addAndReturn(List<File> files, File toAdd, Predicate<File> filterFunction) {
        if (filterFunction.test(toAdd)) {
            files.add(toAdd);
        }
        return files;
    }
1
user1189332

Voici une solution simple mais parfaitement fonctionnelle utilisant recursion:

public static List<Path> listFiles(String rootDirectory)
{
    List<Path> files = new ArrayList<>();
    listFiles(rootDirectory, files);

    return files;
}

private static void listFiles(String path, List<Path> collectedFiles)
{
    File root = new File(path);
    File[] files = root.listFiles();

    if (files == null)
    {
        return;
    }

    for (File file : files)
    {
        if (file.isDirectory())
        {
            listFiles(file.getAbsolutePath(), collectedFiles);
        } else
        {
            collectedFiles.add(file.toPath());
        }
    }
}
1
BullyWiiPlaza

Exemple de sortie de fichiers * .csv dans un répertoire de recherche récursive à l'aide de Files.find () à partir de Java.nio:

String path = "C:/Daten/ibiss/ferret/";
    logger.debug("Path:" + path);
    try (Stream<Path> fileList = Files.find(Paths.get(path), Integer.MAX_VALUE,
            (filePath, fileAttr) -> fileAttr.isRegularFile() && filePath.toString().endsWith("csv"))) {
        List<String> someThingNew = fileList.sorted().map(String::valueOf).collect(Collectors.toList());
        for (String t : someThingNew) {
            t.toString();
            logger.debug("Filename:" + t);
        }

    }

En publiant cet exemple, j’ai eu du mal à comprendre comment passer le paramètre filename dans l’exemple n ° 1 donné par Bryan, en utilisant foreach sur le résultat de flux -

J'espère que cela t'aides.

0
Ralf R.