Java,列出目录中仅包含子目录而非文件的列表

122

在Java中,如何列出目录下仅包含子目录的内容?

我想使用java.io.File功能,那么在Java中怎样做最好呢?

13个回答

166
你可以使用File类来列出目录。
File file = new File("/path/to/directory");
String[] directories = file.list(new FilenameFilter() {
  @Override
  public boolean accept(File current, String name) {
    return new File(current, name).isDirectory();
  }
});
System.out.println(Arrays.toString(directories));

更新

这篇文章的作者在评论中想要一种更快的方法,在此处有很好的讨论: 如何快速地在Java中检索目录列表?

基本上:

  1. 如果你控制文件结构,我会尽量避免进入那种情况。
  2. 在Java NIO.2中,你可以使用directories函数返回一个迭代器以实现更大的扩展性。Directory Stream类是一个对象,你可以用它来迭代一个目录中的条目。

1
嗨,谢谢回复。但是我不需要遍历目录中的所有项目。我需要直接列出目录中的子目录。因为我有很多文件,而目录中只有少数子目录,所以检查isDirectory()会耗费时间。请给我另一种方法。 - Lokesh Paunikar
我更新了我的帖子,特别是请看Jon Skeet对这个问题的评论。还有关于NIO的回应,因为Java NIO 2有一个迭代器用于目录函数,返回一个目录流。 - Mohamed Mansour
你指的是 Skeet 的哪个评论?这里哪个答案性能更好? - Stealth Rabbi

132

一个非常简单的Java 8解决方案:

File[] directories = new File("/your/path/").listFiles(File::isDirectory);

它等同于使用FileFilter(也适用于旧版Java):

File[] directories = new File("/your/path/").listFiles(new FileFilter() {
    @Override
    public boolean accept(File file) {
        return file.isDirectory();
    }
});

5
双冒号::在这个例子中是如何工作的? - snickers10m
1
我注意到没有其他答案使用FileFilter,所以我添加了一个等效版本,而不使用方法引用。有关方法引用的更多信息,请参阅此SO问题或此文章 - headsvk
这个命令会获取子目录还是只获取直接位于 /your/path/ 下的目录? - amadain
1
@amadain 没有递归,正如预期的那样 https://docs.oracle.com/javase/7/docs/api/java/io/File.html#listFiles() - headsvk
将类File中的函数isDirectory作为参数发送。 - Osmar

14

@Mohamed Mansour,你已经接近成功了... 你使用的 "dir" 参数实际上是当前路径,因此它总是返回 true。为了确定子目录是否为子目录,你需要测试该子目录。

File file = new File("/path/to/directory");
String[] directories = file.list(new FilenameFilter() {
  @Override
  public boolean accept(File current, String name) {
    return new File(current, name).isDirectory();
  }
});
System.out.println(Arrays.toString(directories));

8

如果您希望使用Java 7和NIO.2解决方案,可以按照以下步骤进行:

private static class DirectoriesFilter implements Filter<Path> {
    @Override
    public boolean accept(Path entry) throws IOException {
        return Files.isDirectory(entry);
    }
}

try (DirectoryStream<Path> ds = Files.newDirectoryStream(FileSystems.getDefault().getPath(root), new DirectoriesFilter())) {
        for (Path p : ds) {
            System.out.println(p.getFileName());
        }
    } catch (IOException e) {
        e.printStackTrace();
    }

3
ArrayList<File> directories = new ArrayList<File>(
    Arrays.asList(
        new File("your/path/").listFiles(File::isDirectory)
    )
);

你好,欢迎来到StackOverflow!您能详细说明一下您的答案吗?比如解释代码片段中有趣的部分或者提供链接以便进一步阅读文档? - Richard-Degenne
这应该是正确的答案,因为它提供了一个带有完整规范化路径的文件对象。虽然这可能有点老,但还是值得指出一下。 - Jero Dungog

3

这将列出(即打印)所有子目录。它基本上是一种循环,你不需要将项目存储到列表中间。这是大多数人最需要的,所以我在这里留下它。

Path directory = Paths.get("D:\\directory\\to\\list");

Files.walk(directory, 1).filter(entry -> !entry.equals(directory))
    .filter(Files::isDirectory).forEach(subdirectory ->
{
    // do whatever you want with the subdirectories
    System.out.println(subdirectory.getFileName());
});

3
我想使用java.io.File的功能,在2012年(问题的日期)是可以的,但不适用于今天。对于这样的需求,应该优先考虑使用java.nio API。
有很多答案,但我会使用简单的方法Files.walk().filter().collect()
总体上有两种方法可行:
1)Files.walk(Path start, )没有maxDepth限制;
2)Files.walk(Path start, int maxDepth, FileVisitOption... options)允许设置深度限制。
若不指定任何深度限制,则会返回:
Path directory = Paths.get("/foo/bar");

try {
    List<Path> directories =
            Files.walk(directory)
                 .filter(Files::isDirectory)
                 .collect(Collectors.toList());
} catch (IOException e) {
    // process exception
}

如果因为遗留原因,你需要获取一个File列表,那么你只需要在收集之前添加一个map(Path::toFile)操作:

Path directory = Paths.get("/foo/bar");

try {
    List<File> directories =
            Files.walk(directory)
                 .filter(Files::isDirectory)
                 .map(Path::toFile)
                 .collect(Collectors.toList());
} catch (IOException e) {
    // process exception
}

还有一个Files.list(Path),可能与Files.walk(Path,1)相同。 - David L.
@David L确实,如果我们不想递归迭代文件夹,则Files.list(Path)是一个不错的选择。要递归迭代文件夹,最好使用walk() - davidxxx

2
对于那些对Java 7和NIO也感兴趣的人,@voo上面的答案有一个替代方案。我们可以使用调用Files.find()try-with-resources和一个用于过滤目录的lambda函数。
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.stream.Stream;


final Path directory = Paths.get("/path/to/folder");

try (Stream<Path> paths = Files.find(directory, Integer.MAX_VALUE, (path, attributes) -> attributes.isDirectory())) {
    paths.forEach(System.out::println);
} catch (IOException e) {
    ...
}

我们甚至可以通过更改lambda函数按名称过滤目录:
(path, attributes) -> attributes.isDirectory() && path.toString().contains("test")

按日期:
final long now = System.currentTimeMillis();
final long yesterday = new Date(now - 24 * 60 * 60 * 1000L).getTime();

// modified in the last 24 hours
(path, attributes) -> attributes.isDirectory() && attributes.lastModifiedTime().toMillis() > yesterday

1
    File files = new File("src");
    // src is folder name...
    //This will return the list of the subDirectories
    List<File> subDirectories = Arrays.stream(files.listFiles()).filter(File::isDirectory).collect(Collectors.toList());
// this will print all the sub directories
Arrays.stream(files.listFiles()).filter(File::isDirectory).forEach(System.out::println);

0

这是我的代码解决方案。我只做了一个小改动来自第一个答案。这将逐行列出所需目录中的所有文件夹:

try {
            File file = new File("D:\\admir\\MyBookLibrary");
            String[] directories = file.list(new FilenameFilter() {
              @Override
              public boolean accept(File current, String name) {
                return new File(current, name).isDirectory();
              }
            });
            for(int i = 0;i < directories.length;i++) {
                if(directories[i] != null) {
                    System.out.println(Arrays.asList(directories[i]));

                }
            }
        }catch(Exception e) {
            System.err.println("Error!");
        }

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