使用FileUtils.listFiles递归查找仅包含目录的文件夹

18

我想收集一个目录下的所有文件列表,特别是包括子目录。我不想亲自操作,所以我正在使用Apache Commons IO的FileUtils.listFiles。因此,我的代码看起来像这样:

import java.io.File;
import java.util.Collection;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.filefilter.TrueFileFilter;

public class TestListFiles {
  public static void main(String[] args) {
    Collection<File> found = FileUtils.listFiles(new File("foo"),
        TrueFileFilter.INSTANCE, TrueFileFilter.INSTANCE);
    for (File f : found) {
      System.out.println("Found file: " + f);
    }
  }
}

问题在于,这似乎只能找到普通文件,而不能找到目录:

$ mkdir -p foo/bar/baz; touch foo/one_file
$ java -classpath commons-io-1.4.jar:. TestListFiles
Found file: foo/one_file

我已经向这两个过滤器传递了 TrueFileFilter,所以我想不到更加包容的方法了。我希望它列出:"foo","foo/one_file","foo/bar","foo/bar/baz"(以任意顺序)。

我也可以接受非FileUtils 的解决方案,但是写自己的BFS甚至从我得到的列表中收集父目录的集合似乎很傻。 (那样会错过空的子目录。)FWIW,这是在Linux上进行的。

6个回答

21

一个老回答,但这对我有用:

FileUtils.listFilesAndDirs(new File(dir), TrueFileFilter.INSTANCE, DirectoryFileFilter.DIRECTORY);

显示两者:

我使用:

FileUtils.listFilesAndDirs(new File(dir), new NotFileFilter(TrueFileFilter.INSTANCE), DirectoryFileFilter.DIRECTORY)

仅显示目录而不显示文件...


这对我来说比user573041的答案慢得多,以至于我把我的应用程序给卡死了。 - Sridhar Sarnobat
"new NotFileFilter(TrueFileFilter.INSTANCE)" 的替代方案就是 "FalseFileFilter.INSTANCE"。我认为你的答案使用 "FileUtils.listFilesAndDirs(...)" 最合适,这是 OP 所要求的简单解决方案。 - It's Leto
我使用 Collection<File> c = FileUtils.listFilesAndDirs(new File("target"), FalseFileFilter.INSTANCE,TrueFileFilter.INSTANCE); - Anver Sadhat

8

你是否尝试过简单地:

File rootFolder = new File(...);
File[] folders = rootFolder.listFiles((FileFilter) FileFilterUtils.directoryFileFilter());

这对我来说似乎有效。

当然,你需要使用递归。

希望能有所帮助。


1
谢谢,这个对我来说是最好的。我不想为VFS添加另一个库。 - Sridhar Sarnobat
问题在于Java io非常慢。 - Kieveli

6

在我的大部分非平凡应用程序中,我避免使用Java IO库,而是更喜欢使用Commons VFS。我认为使用适当参数调用这个方法就可以实现你的目标,但我承认这需要很长的一段代码来完成功能。

具体来说,以下代码将实现你想要的:

    FileObject[] files = fileObject.findFiles(new FileSelector() {
        public boolean includeFile(FileSelectInfo fileInfo)  {
            return fileInfo.getFile().getType() == FileType.FOLDER; }

        public boolean traverseDescendents(FileSelectInfo fileInfo) {
            return true;
        }
    });

其中fileObject是FileObject的一个实例。


此方法是一个损坏的链接。 - Dave Jarvis

6
如果你查看源代码并阅读JavaDoc之间的内容,你会发现,不幸的是,这个API不是为了实现你想要的功能而设计的。它将返回与提供的参数匹配的文件列表(而不是文件和目录列表)。在源代码中,查看innerListFiles方法,你会发现目录被搜索但未添加到结果列表中。
我不知道是否有任何公共API可以实现你想要的功能。希望其他人能知道。大多数可能是DFS,而不是BFS,这对你的目的可能有所影响。(到目前为止,我看过的所有Java代码都是通过深度优先搜索来执行目录树遍历的。当然,并不意味着不存在BFS。)
如果你真的想要一个给定目录下的所有内容列表,那么自己编写也很容易。但我理解你不想重复造轮子的愿望。
注意:Apache Commons Finder 可能支持您需要的内容,但该库位于Commons Sandbox中,这意味着它目前处于实验阶段。它可能不完整,也可能不被维护。此外,它可能对您正在寻找的内容来说过于笨重。

谢谢你的指针 - 我可能最终会只是复制它并使其工作。我想这就是我因为假设 Linux 上的所有文件(目录、链接、管道、设备)都是 Commons 定义下的文件而得到的结果。 - Dave B
5
如果我在你之前,做出了相同的假设,直到它不起作用。他们真的应该让JavaDoc更加明确,以便清晰明了。 - Eddie
哇,感谢指针。Javadoc中没有提到目录被排除在外的参考资料。我不知道是谁认为目录不是文件! - WhyNotHugo

1
一个更简单和完整的Commons VFS解决方案:
FileSystemManager fsManager = VFS.getManager();
FileObject fileObject = fsManager.resolveFile( "yourFileNameHere" );
FileObject[] files = fileObject.findFiles( new FileTypeSelector( FileType.FOLDER ) )

0

基于他们的API,它应该可以工作。

这是我自己版本的FileUtils,不像Commons IO那么完整,只包含我需要的部分。搜索findFiles或者你可以使用iterate来避免创建大量列表(有时/大多数情况下,你只想对这些文件做一些事情,所以将它们收集到一个列表中是没有意义的)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接