# 创建和读取目录

以前讨论过的一些方法,如 delete 文件,链接和目录。但是如何列出文件系统顶部的所有目录?如何列出目录的内容或创建目录? 本节介绍了目录特有的以下功能:

  • 列出文件系统的根目录
  • 创建目录
  • 创建临时目录
  • 列出目录的内容
  • 使用 Globbing 过滤目录列表
  • 编写自己的目录过滤器

# 列出文件系统的根目录

您可以使用 FileSystem.getRootDirectories 方法列出文件系统的所有根目录 。 此方法返回一个Iterable,它使您能够使用 enhanced for 语句来遍历所有根目录。

以下代码使用默认文件系统打印根目录

Iterable<Path> dirs = FileSystems.getDefault().getRootDirectories();
for (Path name: dirs) {
    System.err.println(name);
    // 在windows系统中的话就是打印各个盘符路径
}
1
2
3
4
5

# 创建目录

您可以使用 createDirectory(Path, FileAttribute<?>) 方法创建一个新的目录 。 如果不指定任何属性 FileAttributes,则新目录将具有默认属性。例如:

Path dir = ...;
Files.createDirectory(path);
1
2

以下代码片段在具有特定权限的 POSIX 文件系统上创建一个新目录:

Set<PosixFilePermission> perms =
    PosixFilePermissions.fromString("rwxr-x---");
FileAttribute<Set<PosixFilePermission>> attr =
    PosixFilePermissions.asFileAttribute(perms);
Files.createDirectory(file, attr);
1
2
3
4
5

当一个或多个父目录可能不存在时,要创建一个目录多个级别深度,可以使用方便的方法 createDirectories(Path, FileAttribute<?>)。 与该 createDirectory(Path, FileAttribute<?>) 方法一样,您可以指定一组可选的初始文件属性。以下代码片段使用默认属性:

Files.createDirectories(Paths.get("foo/bar/test"));
1

根据需要,从上到下创建目录。在该 foo/bar/test 示例中,如果 foo 目录不存在,则创建它。接下来,bar 如果需要,test 创建目录,最后创建该目录。

在创建一些但不是全部的父目录之后,这种方法可能会失败。

# 创建临时目录

您可以使用以下 createTempDirectory 方法之一创建临时目录:

1. createTempDirectory(Path, String, FileAttribute<?>...)
2. createTempDirectory(String, FileAttribute<?>...)
1
2

第一种方法允许代码指定临时目录的位置,第二种方法在默认临时目录中创建一个新目录。

# 列出目录的内容

您可以使用该 newDirectoryStream(Path) 方法列出目录的所有内容 。此方法返回一个实现该接口的 DirectoryStream 对象。 实现接口的类 DirectoryStream 也实现了 Iterable,所以你可以遍历目录流,读取所有的对象。 这种方法可以很好地扩展到非常大的目录。

记住: 返回的 DirectoryStream 是一条流。如果您不使用 try-with-resources 语句, 请不要忘记关闭 finally 块中的流。建议使用 try-with-resources 语句

以下代码片段显示如何打印目录的内容:

Path dir = Paths.get("d:/");
try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir)) {
    for (Path file : stream) {
        System.out.println(file.getFileName());
    }
} catch (IOException | DirectoryIteratorException x) {
    // IOException can never be thrown by the iteration.
    // In this snippet, it can only be thrown by newDirectoryStream.
    System.err.println(x);
}
1
2
3
4
5
6
7
8
9
10

此方法返回目录的全部内容:文件,链接,子目录和隐藏文件。如果您希望对所检索的内容更有选择性,可以使用其他 newDirectoryStream 方法之一,如本页后面所述。

请注意,如果在目录迭代期间 DirectoryIteratorException 有异常,那么将 IOException 作为原因抛出。迭代器方法不能抛出异常异常。

# 使用 Globbing 过滤目录列表

如果要仅获取每个名称与特定模式匹配的文件和子目录,可以使用 newDirectoryStream(Path, String) 提供内置 glob 过滤器的方法来实现。 如果您不熟悉 glob 语法,请参阅 什么是 Glob?

例如,以下代码片段列出了与 Java 有关的文件:.class,.java 和 .jar 文件:

Path dir = Paths.get("d:/");
try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir, "*.{java,class,jar}")) {
    for (Path file : stream) {
        System.out.println(file.getFileName());
    }
} catch (IOException | DirectoryIteratorException x) {
    // IOException can never be thrown by the iteration.
    // In this snippet, it can only be thrown by newDirectoryStream.
    System.err.println(x);
}
1
2
3
4
5
6
7
8
9
10

# 编写自己的目录过滤器

也许你想基于除模式匹配之外的一些条件来过滤目录的内容。您可以通过实现 DirectoryStream.Filter<T> 接口创建自己的过滤器 。 该接口由一个方法 accept 组成,它确定文件是否满足搜索要求。

例如以下代码实现 仅仅检索目录的过滤器:

DirectoryStream.Filter<Path> filter = new DirectoryStream.Filter<Path>() {
    @Override
    public boolean accept(Path entry) throws IOException {
        return entry.toFile().isDirectory();
    }
};
1
2
3
4
5
6

一但创建过滤器,就可以使用 newDirectoryStream(Path, DirectoryStream.Filter<? super Path>) 方法来调用过滤器,如

DirectoryStream<Path> stream = Files.newDirectoryStream(dir, filter)
1

此方法仅用于过滤单个目录。但是,如果要查找文件树中的所有子目录,您将使用“ 文件树” 的机制。