Liste récursive des fichiers en Java

Comment lister récursivement tous les fichiers dans un répertoire en Java? Le cadre fournit aucune utilité?

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

195
demandé sur Adil 2010-01-13 14:29:32

20 réponses

Java 8 fournit un bon flux pour traiter tous les fichiers dans un arbre.

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 sur le résultat telles que la limite, le regroupement, le mappage, la sortie anticipée, etc.

UPDATE : je pourrais souligner qu'il y a aussi des fichiers .find {[10] } qui prend un BiPredicate qui pourrait être plus efficace si vous avez besoin de vérifier les attributs de fichier.

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

Notez que si le JavaDoc élude que cette méthode pourrait être plus efficace que les fichiers .walk il 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 avez besoin de filtrer sur les attributs, utilisez les fichiers .trouvez , sinon utilisez les fichiers .marcher , surtout parce qu'il y a des surcharges et c'est plus pratique.

TESTS : comme demandé, j'ai fourni une comparaison des performances de nombreuses réponses. Vérifier sur le projet Github qui contient des résultats et un cas de test .

233
répondu Brett Ryan 2016-05-04 09:45:45

FileUtils ont iterateFiles et listFiles des méthodes. De leur donner un essai. (à partir de commons-io)

Edit: Vous pouvez vérifier ici pour un benchmark des différentes approches. Il semble que l'approche commons-io soit lente, alors choisissez parmi les plus rapides à partir d'ici (si cela compte)

156
répondu Bozho 2016-07-11 20:12:53

/ / Prêt à fonctionner

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:\\" );
    }

}
128
répondu stacker 2015-04-10 02:35:57

Java 7 sera a Fichiers.walkFileTree :

Si vous fournissez un point de départ et un visiteur de fichier, il invoquera diverses méthodes sur le visiteur de fichier lorsqu'il parcourra le fichier dans l'arborescence des fichiers. Nous nous attendons à ce que les gens 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 Oracle entier tutoriel sur cette question.

66
répondu yawn 2013-04-05 14:42:53

Aucune bibliothèque externe nécessaire.
renvoie une Collection afin que vous puissiez faire ce que vous voulez avec elle 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;
}
23
répondu Petrucio 2016-08-02 17:38:43

J'irais 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 Système.hors.println est juste là pour indiquer de faire quelque chose avec le fichier. il n'est pas nécessaire de faire la différence entre les fichiers et les répertoires, car un fichier normal aura simplement zéro enfant.

16
répondu Stefan Schmidt 2010-01-13 11:39:33

É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;
}
11
répondu pstanton 2010-01-13 11:36:26

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

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);
    }
  }
}
11
répondu benroth 2012-05-30 10:26:45

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
répondu chao 2017-08-15 21:37:34

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 dirs (File la classe A la méthode isDirectory()).

7
répondu Michał Niklas 2010-01-13 11:35:53

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

Files.walk(root.toPath())
      .filter(path -> !Files.isDirectory(path))
      .forEach(path -> System.out.println(path));
4
répondu Roy Kachouh 2014-10-05 12:38:38

En dehors de la traversée récursive, on peut également utiliser une approche basée sur les visiteurs.

Le code ci-dessous utilise une approche basée sur les visiteurs pour le traversal.It on s'attend à ce que l'entrée du programme soit le répertoire racine à parcourir.

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
répondu sateesh 2016-07-19 07:42:16

Vous pouvez utiliser le code ci - dessous pour obtenir une liste de fichiers d'un dossier ou d'un répertoire spécifique de manière récursive.

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());
            }
        }
    }
2
répondu Rakesh Chaudhari 2017-06-23 05:25:44

ce code est prêt à fonctionner

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

public static void getFile(File[] files) {
    for (File file : files) {
        if (file.isDirectory()) {
            getFile(file.listFiles());
        } else {
            System.out.println("File: " + file);
        }
    }
}
2
répondu Ebraheem Alrabee' 2018-09-18 14:02:53

BFS Non récursif avec une seule liste (un exemple particulier est 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
répondu bobah 2013-09-22 10:17:21

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
répondu user1189332 2015-11-08 12:13:20

Exemple de sorties *.fichiers csv dans les sous-répertoires de recherche récursive de répertoire à l'aide de fichiers.find() 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);
        }

    }

Poster cet exemple, car j'ai eu du mal à comprendre comment passer le paramètre filename dans l'exemple #1 donné par Bryan, en utilisant foreach on Stream-result -

J'espère que cela aide.

0
répondu Ralf R. 2017-10-12 10:43:07

Voici une solution simple mais parfaitement fonctionnelle en 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());
        }
    }
}
0
répondu BullyWiiPlaza 2018-01-01 21:06:42
    private void fillFilesRecursively(File file, List<File> resultFiles) {
        if (file.isFile()) {
            resultFiles.add(file);
        } else {
            for (File child : file.listFiles()) {
                fillFilesRecursively(child, resultFiles);
            }
        }
    }
0
répondu legendmohe 2018-06-23 09:05:49

Basé sur la réponse de l'empileur. Voici une solution fonctionnant en JSP sans bibliothèques externes afin que vous puissiez la mettre presque n'importe où sur votre serveur:

<!DOCTYPE html>
<%@ page session="false" %>
<%@ page import="java.util.*" %>
<%@ page import="java.io.*" %>
<%@ page contentType="text/html; charset=UTF-8" %>

<%!
    public List<String> files = new ArrayList<String>();
    /**
        Fills files array with all sub-files.
    */
    public void walk( File root ) {
        File[] list = root.listFiles();

        if (list == null) return;

        for ( File f : list ) {
            if ( f.isDirectory() ) {
                walk( f );
            }
            else {
                files.add(f.getAbsolutePath());
            }
        }
    }
%>
<%
    files.clear();
    File jsp = new File(request.getRealPath(request.getServletPath()));
    File dir = jsp.getParentFile();
    walk(dir);
    String prefixPath = dir.getAbsolutePath() + "/";
%>

Ensuite, vous faites juste quelque chose comme:

    <ul>
        <% for (String file : files) { %>
            <% if (file.matches(".+\\.(apk|ipa|mobileprovision)")) { %>
                <li><%=file.replace(prefixPath, "")%></li>
            <% } %>
        <% } %>
    </ul>
-1
répondu Nux 2014-01-21 09:43:21