Frage

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

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

War es hilfreich?

Lösung

Java 8 bietet einen schönen 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 durchqueren. Da es sich um einen Stream handelt, können Sie alle netten Stream -Operationen für das Ergebnis wie Limit, Gruppierung, Zuordnung, frühzeitig beenden usw. durchführen usw.

AKTUALISIEREN: Ich könnte darauf hinweisen, dass es auch gibt Dateien.find das braucht a Zweibaut Dies 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 sich der Javadoc, während sich diese Methode entzieht, effizienter als Dateien.walk Es ist effektiv identisch, der Leistungsunterschied kann beobachtet werden, wenn Sie auch Dateiattribute in Ihrem Filter abrufen. Am Ende, wenn Sie bei Attributen filtern müssen Dateien.find, ansonsten Dateien.walk, Vor allem, weil es Überlastungen gibt und es bequemer ist.

Tests: Wie angefordert habe ich einen Leistungsvergleich vieler Antworten bereitgestellt. Probier das aus Github -Projekt, das Ergebnisse und einen Testfall enthält.

Andere Tipps

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

Bearbeiten: Sie können überprüfe hier für einen Maßstab verschiedener Ansätze. Es scheint, dass der Commons-io-Ansatz langsam ist. Wählen Sie also einige der schnelleren aus von hier (wenn es wichtig ist)

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

}

Java 7 werde haben hat Dateien.WalkFiletree:

Wenn Sie einen Ausgangspunkt und einen Dateibesucher bereitstellen, werden verschiedene Methoden auf dem Dateibesucher aufgerufen, wenn er die Datei in der Dateistruktur durchläuft. Wir erwarten, dass Personen dies verwenden, wenn sie eine rekursive Kopie, einen rekursiven Umzug, einen rekursiven Löschen oder eine rekursive Operation entwickeln, die Berechtigungen festlegt oder einen weiteren Vorgang für jede der Dateien ausführt.

Es gibt jetzt eine ganze Oracle Tutorial zu dieser Frage.

Keine externen Bibliotheken benötigt.
Gibt eine Sammlung zurück, damit Sie nach dem Anruf alles tun können, was 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;
}

Ich würde mit so etwas gehen wie:

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

Das System.out.println ist nur da, um etwas mit der Datei zu tun. Es ist nicht erforderlich, zwischen Dateien und Verzeichnissen zu unterscheiden, da eine normale Datei einfach null Kinder hat.

Ich bevorzuge es, eine Warteschlange über Rekursion für diese Art von einfacher Durchführung zu verwenden:

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

Schreiben Sie es einfach selbst mit einer einfachen 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;
}

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

Ich denke, das sollte die Arbeit erledigen:

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

Auf diese Weise haben Sie Dateien und Diren. Verwenden Sie nun Rekursion und tun Sie dasselbe für Dires (File Klasse hat isDirectory() Methode).

Dieser Code ist bereit zum Ausführen

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

In Java 8 können wir jetzt das Dateien -Dienstprogramm verwenden, um einen Dateibaum zu erreichen. Sehr einfach.

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

Abgesehen von der rekursiven Durchquerung kann man auch einen Besucheransatz verwenden.

Der unteren Code wird einen besucherbasierten Ansatz für den Traversal verwendet. Es wird erwartet, dass die Eingabe des Programms das Root -Verzeichnis für die Traverse 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);
        }
    }
}

Sie können den folgenden Code verwenden, um eine Liste von Dateien mit bestimmten Ordnern oder Verzeichnissen 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());
            }
        }
    }

Nicht rekursive BFS mit einer einzigen Liste (bestimmtes Beispiel ist 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);
        }
    }

Meine Version (natürlich hätte ich den eingebauten Walk in Java 8 verwenden können ;-)):

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

Hier eine einfache, aber perfekt funktionierende Lösung verwenden 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());
        }
    }
}
    private void fillFilesRecursively(File file, List<File> resultFiles) {
        if (file.isFile()) {
            resultFiles.add(file);
        } else {
            for (File child : file.listFiles()) {
                fillFilesRecursively(child, resultFiles);
            }
        }
    }

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

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

Beispielausgänge *.csv -Dateien im Verzeichnis rekursive Such -Unterverzeichnisse mithilfe von Dateien.find () von 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);
        }

    }

Veröffentlichen dieses Beispiels, da ich Probleme beim Verständnis des Dateinamenparameters in dem von Bryan angegebenen Beispiel für den Dateinamen in Stream -Result -hatte -

Hoffe das hilft.

Basierend auf der Stacker -Antwort. Hier ist eine Lösung, die in JSP ohne externe Bibliotheken arbeitet, damit Sie sie fast überall auf Ihrem Server setzen können:

<!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() + "/";
%>

Dann machst du einfach so etwas wie:

    <ul>
        <% for (String file : files) { %>
            <% if (file.matches(".+\\.(apk|ipa|mobileprovision)")) { %>
                <li><%=file.replace(prefixPath, "")%></li>
            <% } %>
        <% } %>
    </ul>
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top