该Java教程是针对JDK 8编写的。本页面描述的示例和实践不利用后续版本引入的改进,并可能使用不再可用的技术。
有关Java SE 9和后续版本中更新的语言功能的摘要,请参阅Java语言变化。
有关所有JDK版本的新功能、增强功能和已删除或已弃用选项的信息,请参阅JDK发行说明。
之前讨论的一些方法,如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
方法之一创建临时目录:
createTempDirectory(Path, String, FileAttribute<?>...)
createTempDirectory(String, FileAttribute<?>...)
第一个方法允许代码指定临时目录的位置,而第二个方法在默认临时文件目录中创建一个新目录。
您可以使用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); }
此方法仅用于过滤单个目录。如果要查找文件树中的所有子目录,则应使用遍历文件树的机制。