wake-up-neo.com

Listen Sie Dateien rekursiv in Java

Wie liste ich rekursiv alle Dateien unter einem Verzeichnis in Java auf? Bietet das Framework einen Nutzen?

Ich habe viele hackige Implementierungen gesehen. Aber keine aus dem Rahmen oder nio

234
Quintin Par

Java 8 bietet einen Nice-Stream, um alle Dateien in einem Baum zu verarbeiten.

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

Dies bietet eine natürliche Möglichkeit, Dateien zu durchlaufen. Da es sich um einen Stream handelt, können Sie alle Nice-Stream-Vorgänge für das Ergebnis ausführen, z. B. Begrenzen, Gruppieren, Zuordnen, vorzeitiges Beenden usw.

[~ # ~] Update [~ # ~] : Ich könnte darauf hinweisen, dass es auch Files.find gibt, das eine BiPredicate das könnte effizienter sein, wenn Sie Dateiattribute überprüfen müssen.

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

Beachten Sie, dass das JavaDoc nicht der Ansicht ist, dass diese Methode effizienter als Files.walk ist. Der Leistungsunterschied kann jedoch beobachtet werden, wenn Sie auch Dateiattribute in Ihrem Filter abrufen. Wenn Sie am Ende nach Attributen filtern müssen, verwenden Sie Files.find , andernfalls Files.walk , hauptsächlich, weil es Überladungen gibt und dies praktischer ist.

[~ # ~] Tests [~ # ~] : Wie angefordert habe ich einen Leistungsvergleich für viele der Antworten bereitgestellt. Schauen Sie sich das Github-Projekt an, das Ergebnisse und einen Testfall enthält .

285
Brett Ryan

FileUtils haben iterateFiles und listFiles Methoden. Probieren Sie es aus. (von commons-io )

Bearbeiten: Sie können hier überprüfen für einen Benchmark verschiedener Ansätze. Es scheint, dass der Commons-io-Ansatz langsam ist, also wählen Sie einige der schnelleren aus von hier aus (wenn es darauf ankommt)

158
Bozho

// Bereit zu rennen

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 werde haben hat Files.walkFileTree :

Wenn Sie einen Startpunkt und einen Dateibesucher angeben, werden beim Durchlaufen der Datei in der Dateibaumstruktur verschiedene Methoden für den Dateibesucher aufgerufen. Wir erwarten, dass die Benutzer dies verwenden, wenn sie eine rekursive Kopie, eine rekursive Verschiebung, ein rekursives Löschen oder eine rekursive Operation entwickeln, die Berechtigungen festlegt oder eine andere Operation für jede der Dateien ausführt.

Es gibt jetzt ein vollständiges Oracle-Tutorial zu dieser Frage .

66
yawn

Keine externen Bibliotheken erforderlich.
Gibt eine Sammlung zurück, sodass Sie nach dem Anruf mit ihr arbeiten können, was immer Sie wollen.

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

Ich würde mit etwas gehen wie:

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

Die Datei "System.out.println" gibt nur an, dass mit der Datei etwas geschehen soll. Es ist nicht erforderlich, zwischen Dateien und Verzeichnissen zu unterscheiden, da eine normale Datei lediglich null untergeordnete Dateien enthält.

17
Stefan Schmidt

Ich bevorzuge die Verwendung einer Warteschlange gegenüber der Rekursion für diese Art der einfachen Überquerung:

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

schreibe es einfach selbst mit einfacher Rekursion:

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

Mit Java 7 können Sie die folgende Klasse verwenden:

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

Dieser Code ist betriebsbereit

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

Ich denke, das sollte die Arbeit machen:

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

Auf diese Weise haben Sie Dateien und Verzeichnisse. Verwenden Sie jetzt die Rekursion und machen Sie dasselbe für dirs (File Klasse hat isDirectory() Methode).

7
Michał Niklas

In Java 8 können wir jetzt das Dienstprogramm "Files" verwenden, um einen Dateibaum zu durchsuchen. Sehr einfach.

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

Neben dem rekursiven Durchlaufen kann auch ein Besucher-basierter Ansatz verwendet werden.

Der folgende Code verwendet einen besucherbasierten Ansatz für die Durchquerung. Es wird erwartet, dass die Eingabe in das Programm das zu durchquerende Stammverzeichnis ist.

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

Sie können den folgenden Code verwenden, um eine Liste der Dateien eines bestimmten Ordners oder Verzeichnisses rekursiv abzurufen.

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

Nicht rekursives BFS mit einer einzelnen Liste (spezielles Beispiel für die Suche nach * .eml-Dateien):

    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

Ich habe mir das ausgedacht, um alle Dateien/Dateinamen rekursiv auszudrucken.

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

Meine Version (natürlich hätte ich das eingebaute Walk-In verwenden können 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

Hier eine einfache, aber perfekt funktionierende Lösung mit 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

Beispiel für die Ausgabe von * .csv-Dateien in verzeichnisrekursiven Unterverzeichnissen mit Files.find () aus 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);
        }

    }

Als ich dieses Beispiel postete, hatte ich Probleme zu verstehen, wie man den Dateinamen-Parameter in dem von Bryan gegebenen Beispiel Nr. 1 mit foreach auf Stream-result übergibt.

Hoffe das hilft.

0
Ralf R.