文档

Java™ 教程
隐藏目录
创建和读取目录
指南:基本Java类
课程:基本输入输出
章节:文件输入输出(使用NIO.2)

创建和读取目录

之前讨论的一些方法,如delete,可以用于文件、链接和目录。但是如何列出文件系统顶部的所有目录?如何列出目录的内容或创建一个目录?

本节介绍了以下与目录相关的功能:

列出文件系统的根目录

您可以使用FileSystem.getRootDirectories方法列出文件系统的所有根目录。该方法返回一个Iterable,使您可以使用增强的for循环语句遍历所有根目录。

下面的代码片段打印默认文件系统的根目录:

Iterable<Path> dirs = FileSystems.getDefault().getRootDirectories();
for (Path name: dirs) {
    System.err.println(name);
}

创建一个目录

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

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

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

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

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

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

会按需从顶部向下创建目录。在foo/bar/test的示例中,如果foo目录不存在,则会创建它。然后,如果需要,将创建bar目录,最后创建test目录。

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

创建临时目录

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

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

列出目录的内容

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


注意: 返回的DirectoryStream是一个流。如果您没有使用try-with-resources语句,请不要忘记在finally块中关闭流。try-with-resources语句会为您处理此操作。

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

Path dir = ...;
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);
}

迭代器返回的Path对象是相对于目录解析的条目的名称。所以,如果你要列出/tmp目录的内容,条目的形式是/tmp/a/tmp/b,依此类推。

这个方法返回整个目录的内容:文件、链接、子目录和隐藏文件。如果你想更有选择性地获取内容,可以使用其中一个其他的newDirectoryStream方法,后面的页面将对此进行详细描述。

注意,如果在目录迭代过程中发生异常,那么将抛出DirectoryIteratorException,异常的原因是IOException。迭代器方法不能抛出异常。

通过使用通配符过滤目录列表

如果你只想获取每个名称与特定模式匹配的文件和子目录,可以使用newDirectoryStream(Path, String)方法,它提供了内置的通配符过滤器。如果你不熟悉通配符语法,请参阅什么是通配符?

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

Path dir = ...;
try (DirectoryStream<Path> stream =
     Files.newDirectoryStream(dir, "*.{java,class,jar}")) {
    for (Path entry: stream) {
        System.out.println(entry.getFileName());
    }
} catch (IOException x) {
    // 迭代过程中不会抛出IOException异常。
    // 在这个示例中,它只能由newDirectoryStream抛出。
    System.err.println(x);
}

编写自己的目录过滤器

也许你想根据某些条件而不是模式匹配来过滤目录的内容。你可以通过实现DirectoryStream.Filter<T>接口来创建自己的过滤器。该接口只包含一个accept方法,该方法确定一个文件是否满足搜索要求。

例如,以下代码段实现了一个只检索目录的过滤器:

DirectoryStream.Filter<Path> filter =
    newDirectoryStream.Filter<Path>() {
    public boolean accept(Path file) throws IOException {
        try {
            return (Files.isDirectory(path));
        } catch (IOException x) {
            // 无法确定它是否是一个目录。
            System.err.println(x);
            return false;
        }
    }
};

创建过滤器后,可以使用newDirectoryStream(Path, DirectoryStream.Filter<? super Path>)方法来调用它。以下代码片段使用isDirectory过滤器仅将目录的子目录打印到标准输出:

Path dir = ...;
try (DirectoryStream<Path>
                       stream = Files.newDirectoryStream(dir, filter)) {
    for (Path entry: stream) {
        System.out.println(entry.getFileName());
    }
} catch (IOException x) {
    System.err.println(x);
}

此方法仅用于过滤单个目录。如果要查找文件树中的所有子目录,则应使用遍历文件树的机制


上一页: 随机访问文件
下一页: 链接,符号或其他方式