it-swarm.dev

Рекурсивный список файлов в Java

Как мне рекурсивно перечислить все файлы в каталоге в Java? Предоставляет ли фреймворк какую-либо полезность?

Я видел много хакерских реализаций. Но ни один из рамок или nio

224
Quintin Par

Java 8 предоставляет поток Nice для обработки всех файлов в дереве.

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

Это обеспечивает естественный способ обхода файлов. Поскольку это поток, вы можете выполнять все операции потока Nice с результатом, такие как ограничение, группировка, отображение, ранний выход и т.д.

UPDATE: я мог бы указать, что есть также Files.find , который принимает BiPredicate это может быть более эффективным, если вам нужно проверить атрибуты файла.

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

Обратите внимание, что, хотя JavaDoc не допускает, что этот метод может быть более эффективным, чем Files.walk , он фактически идентичен, различие в производительности можно наблюдать, если вы также извлекаете атрибуты файла в своем фильтре. В конце концов, если вам нужно фильтровать атрибуты, используйте Files.find , в противном случае используйте Files.walk , в основном потому, что есть перегрузки, и это более удобно.

TESTS: В соответствии с просьбой я предоставил сравнение производительности многих ответов. Проверьте проект Github, который содержит результаты и контрольный пример .

270
Brett Ryan

FileUtils имеют iterateFiles и listFiles методы. Дай им попробовать. (от commons-io )

Правка: Вы можете проверьте здесь для сравнения различных подходов. Кажется, что подход commons-io медленный, поэтому выберите несколько более быстрых отсюда (если это имеет значение)

158
Bozho

// Готов к запуску

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

}
132
stacker

Java 7 буду иметь имеет Files.walkFileTree :

Если вы укажете начальную точку и посетителя файла, он будет вызывать различные методы для посетителя файла, когда он просматривает файл в дереве файлов. Мы ожидаем, что люди будут использовать это, если они разрабатывают рекурсивную копию, рекурсивное перемещение, рекурсивное удаление или рекурсивную операцию, которая устанавливает разрешения или выполняет другую операцию для каждого из файлов.

Теперь есть целый учебник Oracle по этому вопросу .

66
yawn

Внешние библиотеки не нужны.
Возвращает коллекцию, чтобы вы могли делать с ней все, что захотите после звонка.

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

Я хотел бы пойти с чем-то вроде:

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

System.out.println просто указывает, что нужно что-то делать с файлом. нет необходимости различать файлы и каталоги, так как обычный файл просто не имеет дочерних элементов.

16
Stefan Schmidt

просто напишите это самостоятельно, используя простую рекурсию:

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
pstanton

Я предпочитаю использовать очередь, а не рекурсию для такого простого обхода:

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
benroth

С Java 7 вы можете использовать следующий класс:

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

Я думаю, что это должно сделать работу:

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

Таким образом, у вас есть файлы и каталоги. Теперь используйте рекурсию и сделайте то же самое для dirs (класс File имеет метод isDirectory()).

7
Michał Niklas

В Java 8 теперь мы можем использовать утилиту Files для обхода файлового дерева. Очень просто.

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

Этот код готов к запуску

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);
        }
    }
}
5
Ebraheem Alrabee'

Помимо рекурсивного обхода можно использовать подход, основанный на посетителях.

В приведенном ниже коде для обхода используется подход, основанный на посетителях. Ожидается, что вход в программу является корневым каталогом для прохождения.

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

Вы можете использовать приведенный ниже код для рекурсивного получения списка файлов определенной папки или каталога.

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 с одним списком (конкретный пример - поиск файлов * .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
    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

Моя версия (конечно, я мог бы использовать встроенную прогулку в 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

Пример выводит файлы * .csv в подкаталоги рекурсивного поиска в каталоге с помощью Files.find () из 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);
        }

    }

После публикации этого примера у меня возникли проблемы с пониманием того, как передать параметр имени файла в примере №1, заданном Брайаном, с использованием foreach в Stream-result -

Надеюсь это поможет.

0
Ralf R.

Вот простое, но отлично работающее решение с использованием 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
BullyWiiPlaza