Рекурсивный список файлов в Java - PullRequest
229 голосов
/ 13 января 2010

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

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

Ответы [ 20 ]

276 голосов
/ 03 июня 2014

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

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

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

ОБНОВЛЕНИЕ : Я мог бы отметить, что есть также 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 , в основном из-за перегрузок, и это более удобно.

ИСПЫТАНИЯ : В соответствии с просьбой я дал сравнение производительности многих ответов. Проверьте проект Github, который содержит результаты и контрольный пример .

158 голосов
/ 13 января 2010

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

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

132 голосов
/ 13 января 2010

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

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

}
66 голосов
/ 13 января 2010

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

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

В настоящее время существует целое руководство по Oracle по этому вопросу .

25 голосов
/ 26 июля 2012

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

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;
}
17 голосов
/ 13 января 2010

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

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

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

11 голосов
/ 30 мая 2012

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

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 голосов
/ 13 января 2010

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

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;
}
8 голосов
/ 22 ноября 2014

С 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;
    }
}
7 голосов
/ 13 января 2010

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

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

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

...