The Java Tutorials have been written for JDK 8.Java教程是为JDK 8编写的。Examples and practices described in this page don't take advantage of improvements introduced in later releases and might use technology no longer available.本页中描述的示例和实践没有利用后续版本中引入的改进,并且可能使用不再可用的技术。See Java Language Changes for a summary of updated language features in Java SE 9 and subsequent releases.有关Java SE 9及其后续版本中更新的语言特性的摘要,请参阅Java语言更改。
See JDK Release Notes for information about new features, enhancements, and removed or deprecated options for all JDK releases.有关所有JDK版本的新功能、增强功能以及已删除或不推荐的选项的信息,请参阅JDK发行说明。
Do you need to create an application that will recursively visit all the files in a file tree? 您是否需要创建一个递归访问文件树中所有文件的应用程序?Perhaps you need to delete every 也许您需要删除树中的每个.class file in a tree, or find every file that hasn't been accessed in the last year. .class文件,或者查找去年未访问过的每个文件。You can do so with the 您可以使用FileVisitor interface.FileVisitor界面执行此操作。
This section covers the following:本节包括以下内容:
To walk a file tree, you first need to implement a 要遍历文件树,首先需要实现FileVisitor. FileVisitor。A FileVisitor specifies the required behavior at key points in the traversal process: when a file is visited, before a directory is accessed, after a directory is accessed, or when a failure occurs. FileVisitor在遍历过程中的关键点指定所需的行为:访问文件时、访问目录前、访问目录后或发生故障时。The interface has four methods that correspond to these situations:该接口有四种对应于这些情况的方法:
preVisitDirectory – postVisitDirectory – visitFile – BasicFileAttributes is passed to the method, or you can use the file attributes package to read a specific set of attributes. BasicFileAttributes被传递给该方法,或者您可以使用文件属性包来读取一组特定的属性。DosFileAttributeView to determine if the file has the "hidden" bit set.DosFileAttributeView,以确定文件是否设置了“隐藏”位。visitFileFailed – If you don't need to implement all four of the 如果不需要实现所有四个FileVisitor methods, instead of implementing the FileVisitor interface, you can extend the SimpleFileVisitor class. FileVisitor方法,而不是实现FileVisitor接口,那么可以扩展SimpleFileVisitor类。This class, which implements the 此类实现FileVisitor interface, visits all files in a tree and throws an IOError when an error is encountered. FileVisitor接口,访问树中的所有文件,并在遇到错误时抛出IOError。You can extend this class and override only the methods that you require.可以扩展此类并仅重写所需的方法。
Here is an example that extends 下面是一个扩展SimpleFileVisitor to print all entries in a file tree. SimpleFileVisitor以打印文件树中所有条目的示例。It prints the entry whether the entry is a regular file, a symbolic link, a directory, or some other "unspecified" type of file. 无论条目是常规文件、符号链接、目录还是其他“未指定”类型的文件,它都会打印条目。It also prints the size, in bytes, of each file. Any exception that is encountered is printed to the console.它还打印每个文件的大小(以字节为单位)。遇到的任何异常都会打印到控制台。
The FileVisitor methods are shown in bold:FileVisitor方法以粗体显示:
import static java.nio.file.FileVisitResult.*;
public static class PrintFiles
extends SimpleFileVisitor<Path> {
// Print information about
// each type of file.
@Override
public FileVisitResult visitFile(Path file,
BasicFileAttributes attr) {
if (attr.isSymbolicLink()) {
System.out.format("Symbolic link: %s ", file);
} else if (attr.isRegularFile()) {
System.out.format("Regular file: %s ", file);
} else {
System.out.format("Other: %s ", file);
}
System.out.println("(" + attr.size() + "bytes)");
return CONTINUE;
}
// Print each directory visited.
@Override
public FileVisitResult postVisitDirectory(Path dir,
IOException exc) {
System.out.format("Directory: %s%n", dir);
return CONTINUE;
}
// If there is some error accessing
// the file, let the user know.
// If you don't override this method
// and an error occurs, an IOException
// is thrown.
@Override
public FileVisitResult visitFileFailed(Path file,
IOException exc) {
System.err.println(exc);
return CONTINUE;
}
}Once you have implemented your 一旦实现了FileVisitor, how do you initiate the file walk? FileVisitor,如何启动文件漫游?There are two walkFileTree methods in the Files class.Files类中有两个walkFileTree方法。
The first method requires only a starting point and an instance of your 第一种方法只需要FileVisitor. FileVisitor的起点和实例。You can invoke the 您可以按如下方式调用PrintFiles file visitor as follows:PrintFiles文件访问者:
Path startingDir = ...; PrintFiles pf = new PrintFiles(); Files.walkFileTree(startingDir, pf);
The second 第二个walkFileTree method enables you to additionally specify a limit on the number of levels visited and a set of FileVisitOption enums. walkFileTree方法使您能够另外指定访问的级别数限制和一组FileVisitOption枚举。If you want to ensure that this method walks the entire file tree, you can specify 如果要确保此方法遍历整个文件树,可以为“最大深度”参数指定Integer.MAX_VALUE for the maximum depth argument.Integer.MAX_VALUE。
You can specify the 您可以指定FileVisitOption enum, FOLLOW_LINKS, which indicates that symbolic links should be followed.FileVisition枚举,FOLLOW_LINKS,这表示应该遵循符号链接。
This code snippet shows how the four-argument method can be invoked:此代码段显示了如何调用四参数方法:
import static java.nio.file.FileVisitResult.*; Path startingDir = ...; EnumSet<FileVisitOption> opts = EnumSet.of(FOLLOW_LINKS); Finder finder = new Finder(pattern); Files.walkFileTree(startingDir, opts, Integer.MAX_VALUE, finder);
A file tree is walked depth first, but you cannot make any assumptions about the iteration order that subdirectories are visited.文件树是深度优先的,但不能对访问子目录的迭代顺序做出任何假设。
If your program will be changing the file system, you need to carefully consider how you implement your 如果您的程序将更改文件系统,则需要仔细考虑如何实现FileVisitor.FileVisitor。
For example, if you are writing a recursive delete, you first delete the files in a directory before deleting the directory itself. 例如,如果要编写递归删除,则首先删除目录中的文件,然后再删除目录本身。In this case, you delete the directory in 在本例中,您将删除postVisitDirectory.postVisitDirectory中的目录。
If you are writing a recursive copy, you create the new directory in 如果要编写递归副本,请在尝试将文件复制到preVisitDirectory before attempting to copy the files to it (in visitFiles). preVisitDirectory(在visitFiles中)之前,在preVisitDirectory中创建新目录。If you want to preserve the attributes of the source directory (similar to the UNIX 如果希望保留源目录的属性(类似于UNIX cp -p command), you need to do that after the files have been copied, in postVisitDirectory. cp -p命令),则需要在复制文件后在postVisitDirectory中执行此操作。The Copy example shows how to do this.Copy示例演示了如何执行此操作。
If you are writing a file search, you perform the comparison in the 如果要编写文件搜索,请在visitFile method. visitFile方法中执行比较。This method finds all the files that match your criteria, but it does not find the directories. 此方法查找所有符合条件的文件,但找不到目录。If you want to find both files and directories, you must also perform the comparison in either the 如果要同时查找文件和目录,还必须在preVisitDirectory or postVisitDirectory method. preVisitDirectory或postVisitDirectory方法中执行比较。The Find example shows how to do this.Find示例演示了如何执行此操作。
You need to decide whether you want symbolic links to be followed. 您需要决定是否要遵循符号链接。If you are deleting files, for example, following symbolic links might not be advisable. 例如,如果要删除文件,则不建议使用以下符号链接。If you are copying a file tree, you might want to allow it. 如果要复制文件树,可能需要允许它。By default, 默认情况下,walkFileTree does not follow symbolic links.walkFileTree不跟随符号链接。
The 为文件调用visitFile method is invoked for files. visitFile方法。If you have specified the 如果指定了FOLLOW_LINKS option and your file tree has a circular link to a parent directory, the looping directory is reported in the visitFileFailed method with the FileSystemLoopException. FOLLOW_LINKS选项,并且文件树具有指向父目录的循环链接,则会在visitFileFailed方法中报告循环目录,并显示FileSystemLoopException。The following code snippet shows how to catch a circular link and is from the 下面的代码片段显示了如何捕获循环链接,它来自Copy example:Copy示例:
@Override
public FileVisitResult
visitFileFailed(Path file,
IOException exc) {
if (exc instanceof FileSystemLoopException) {
System.err.println("cycle detected: " + file);
} else {
System.err.format("Unable to copy:" + " %s: %s%n", file, exc);
}
return CONTINUE;
}This case can occur only when the program is following symbolic links.只有当程序遵循符号链接时,才会发生这种情况。
Perhaps you want to walk the file tree looking for a particular directory and, when found, you want the process to terminate. 也许您希望遍历文件树以查找特定目录,当找到该目录时,您希望进程终止。Perhaps you want to skip specific directories.也许您想跳过特定的目录。
The FileVisitor methods return a FileVisitResult value. FileVisitor方法返回FileVisitResult值。You can abort the file walking process or control whether a directory is visited by the values you return in the 您可以中止文件遍历过程或控制FileVisitor methods:FileVisitor方法中返回的值是否访问目录:
CONTINUE – preVisitDirectory method returns CONTINUE, the directory is visited.preVisitDirectory方法返回CONTINUE,则访问该目录。TERMINATE – SKIP_SUBTREE – preVisitDirectory returns this value, the specified directory and its subdirectories are skipped. preVisitDirectory返回此值时,将跳过指定的目录及其子目录。SKIP_SIBLINGS – preVisitDirectory returns this value, the specified directory is not visited, postVisitDirectory is not invoked, and no further unvisited siblings are visited. preVisitDirectory返回此值时,指定的目录不会被访问,postVisitDirectory不会被调用,也不会访问其他未访问的同级目录。postVisitDirectory method, no further siblings are visited. postVisitDirectory方法返回,则不会访问其他同级。In this code snippet, any directory named 在此代码段中,将跳过任何名为SCCS is skipped:SCCS的目录:
import static java.nio.file.FileVisitResult.*;
public FileVisitResult
preVisitDirectory(Path dir,
BasicFileAttributes attrs) {
(if (dir.getFileName().toString().equals("SCCS")) {
return SKIP_SUBTREE;
}
return CONTINUE;
}In this code snippet, as soon as a particular file is located, the file name is printed to standard output, and the file walking terminates:在此代码段中,一旦找到特定文件,文件名将打印到标准输出,文件遍历将终止:
import static java.nio.file.FileVisitResult.*;
// The file we are looking for.
Path lookingFor = ...;
public FileVisitResult
visitFile(Path file,
BasicFileAttributes attr) {
if (file.getFileName().equals(lookingFor)) {
System.out.println("Located file: " + file);
return TERMINATE;
}
return CONTINUE;
}The following examples demonstrate the file walking mechanism:以下示例演示了文件遍历机制:
Find – Chmod – Copy – WatchDir – -r option watches an entire tree for changes. -r选项调用此程序将监视整个树的更改。