Java 教程是为 JDK 8 编写的。本页中描述的示例和实践未利用在后续版本中引入的改进。
前面讨论过的一些方法,例如 delete
,可以处理文件,链接 和 目录。但是如何列出文件系统顶部的所有目录?如何列出目录的内容或创建目录?
本节介绍以下特定于目录的功能:
你可以使用 FileSystem.getRootDirectories
方法列出文件系统的所有根目录。此方法返回 Iterable
,这使你可以使用 enhanced 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
方法之一创建临时目录:
createTempDirectory(Path, String, FileAttribute<?>...)
createTempDirectory(String, FileAttribute<?>...)
第一种方法允许代码指定临时目录的位置,第二种方法在默认的 temporary-fle 目录中创建新目录。
你可以使用 newDirectoryStream(Path)
方法列出目录的所有内容。此方法返回实现 DirectoryStream
接口的对象。实现 DirectoryStream
接口的类也实现了 Iterable
,因此你可以遍历目录流,读取所有对象。这种方法适用于非常大的目录。
DirectoryStream
是 stream。如果你没有使用 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)
方法来实现此目的,该方法提供了内置的 glob 过滤器。如果你不熟悉 glob 语法,请参阅 What Is a Glob?
例如,以下代码段列出了与 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 can never be thrown by the iteration. // In this snippet, it can // only be thrown by 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) { // Failed to determine if it's a directory. 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); }
此方法仅用于过滤单个目录。但是,如果要查找文件树中的所有子目录,可以使用 Walking the File Tree 的机制。