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
选项调用此程序将监视整个树的更改。