以Java的形式递归列出文件

Qui*_*Par 240 java recursion nio file java-7

如何以递归方式列出Java中目录下的所有文件?框架是否提供任何实用程序?

我看到很多hacky实现.但没有来自框架或nio

Bre*_*yan 296

Java 8提供了一个很好的流来处理树中的所有文件.

Files.walk(Paths.get(path))
        .filter(Files::isRegularFile)
        .forEach(System.out::println);
Run Code Online (Sandbox Code Playgroud)

这提供了一种遍历文件的自然方式.由于它是一个流,你可以对结果进行所有不错的流操作,如限制,分组,映射,早退等.

更新:我可能会指出还有Files.find,它需要一个BiPredicate,如果你需要检查文件属性可以更有效.

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

请注意,虽然JavaDoc认为此方法可能比Files.walk更有效,它实际上是相同的,如果您还要在过滤器中检索文件属性,则可以观察到性能上的差异.最后,如果你需要过滤属性使用Files.find,否则使用Files.walk,主要是因为有重载并且它更方便.

测试:根据要求,我提供了许多答案的性能比较.查看包含结果和测试用例Github项目.

  • 其中一个例子可以显示功能编程的魔力,即使对于初学者也是如此. (5认同)
  • 如何从中获取实际的文件列表? (4认同)
  • 与Java 8之前的方法相比,此方法的性能如何?我当前的目录遍历速度太慢,我正在寻找可以加快速度的方法。 (2认同)
  • @BrettRyan,我尝试了您的解决方案,但在线程“main” java.io.UncheckedIOException: java.nio.file.AccessDeniedException 中出现异常`异常。我怎么能纠正它 (2认同)
  • Files.walk 看起来不错,但通常是无用的......如果你连一个文件都没有访问权限,它会抛出异常......而你什么也没有...... (2认同)

Boz*_*zho 158

FileUtilsiterateFileslistFiles方法.试一试.(来自commons-io)

编辑:您可以在此处查看不同方法的基准.似乎commons-io方法很慢,所以从这里选择一些更快的(如果重要的话)

  • FYI/TLDR:如果你只想递归列出所有文件而不进行过滤,请执行`FileUtils.listFiles(dir,TrueFileFilter.INSTANCE,TrueFileFilter.INSTANCE)`,其中`dir`是一个指向基目录的File对象. (39认同)
  • 你可能想要考虑使用`listFilesAndDirs()`,因为`listFiles()`不会返回空文件夹. (2认同)

sta*_*ker 132

//准备好了

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

}
Run Code Online (Sandbox Code Playgroud)

  • 请注意,对于指向路径层次结构中较高路径的符号链接,将导致该方法永不结束.考虑一个带符号链接的路径,指向` - > .`. (9认同)
  • 这实际上是Files.walkFileTree的糟糕实现.我建议人们看看FIles.walkFileTree而不是试图自己滚动它...它已经处理了@BrettRyan指出的确切问题. (2认同)

yaw*_*awn 66

Java 7 拥有Files.walkFileTree:

如果您提供起点和文件访问者,它将在文件访问者调用文件树中的文件时调用各种方法.我们希望人们在开发递归副本,递归移动,递归删除或递归操作时使用它,这些操作可以设置权限或对每个文件执行其他操作.

现在有关于这个问题的整个Oracle教程.


Pet*_*cio 25

无需外部库.
返回一个Collection,这样你就可以在调用后用它做任何你想做的事情.

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;
}
Run Code Online (Sandbox Code Playgroud)


Ste*_*idt 17

我会用以下的东西:

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

System.out.println就是指示对文件执行某些操作.没有必要区分文件和目录,因为普通文件只有零个孩子.

  • 从`listFiles()`的文档:"如果这个抽象路径名不表示目录,那么这个方法返回`null`." (6认同)

ben*_*oth 13

我更喜欢使用队列而不是递归来进行这种简单的转换:

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);
    }
  }
}
Run Code Online (Sandbox Code Playgroud)


pst*_*ton 12

只需使用简单的递归自己编写:

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;
}
Run Code Online (Sandbox Code Playgroud)


cha*_*hao 8

使用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;
    }
}
Run Code Online (Sandbox Code Playgroud)


Mic*_*las 7

我认为这应该做的工作:

File dir = new File(dirname);
String[] files = dir.list();
Run Code Online (Sandbox Code Playgroud)

这样你就有了文件和目录.现在使用递归并对dirs执行相同的操作(File类有isDirectory()方法).

  • “使用递归”没有帮助。应该有一个例子来说明如何进行。 (2认同)

Roy*_*ouh 7

在Java 8中,我们现在可以使用Files实用程序来遍历文件树.非常简单.

Files.walk(root.toPath())
      .filter(path -> !Files.isDirectory(path))
      .forEach(path -> System.out.println(path));
Run Code Online (Sandbox Code Playgroud)


Ebr*_*ee' 7

该代码可以运行了

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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)