FileVisitor
API可以递归地处理文件树中的所有文件和目录。当要对文件树中的所有或某些文件或目录执行某些操作时,FileVisitor
API非常有用。
SimpleFileVisitor
类是FileVisitor
接口的基本实现。当访问文件/目录时,SimpleFileVisitor
类不执行任何操作。可以从SimpleFileVisitor
类继承文件访问-FileVisitor
类,并且只覆盖需要的方法。
FileVisitor
接口的方法
编号 | 含义 |
---|---|
1 | FileVisitResult preVisitDirectory(T dir, BasicFileAttributes attrs) 在访问目录中的条目之前调用一次。 |
2 | FileVisitResult postVisitDirectory(T dir,IOException exc) 已访问目录中的后调用项。如果在目录的迭代期间抛出了任何异常,则将异常对象作为第二个参数传递给此方法。如果此方法的第二个参数为null ,则在目录迭代期间没有异常。 |
3 | FileVisitResult visitFile(T file, BasicFileAttributes attrs) 是在当访问目录中的文件时调用。 |
4 | FileVisitResult visitFileFailed(T file, IOException exc) 是当由于任何原因而无法访问文件或目录时调用。 |
下表列出了FileVisitResult
的枚举常量及其说明 -
枚举常量 | 描述/含义 |
---|---|
CONTINUE | 继续处理 |
SKIP_SIBLINGS | 继续处理而不访问文件或目录的同级。 |
SKIP_SUBTREE | 继续处理,而不访问目录中的条目。 |
TERMINATE | 终止文件访问过程。 |
不需要在文件访问类的所有四个方法中编写逻辑。要复制目录,请使用preVisitDirectory()
方法来创建一个新目录,并使用visitFile()
方法来复制该文件。
以下代码显示如何打印目录的子目录和文件的名称。
import static java.nio.file.FileVisitResult.CONTINUE
import java.io.IOException
import java.nio.file.FileVisitResult
import java.nio.file.FileVisitor
import java.nio.file.Files
import java.nio.file.Path
import java.nio.file.Paths
import java.nio.file.SimpleFileVisitor
import java.nio.file.attribute.BasicFileAttributes
public class Main {
public static void main(String[] args) {
Path startDir = Paths.get("")
FileVisitor<Path> visitor = getFileVisitor()
try {
Files.walkFileTree(startDir, visitor)
} catch (IOException e) {
e.printStackTrace()
}
}
public static FileVisitor<Path> getFileVisitor() {
class DirVisitor<Path> extends SimpleFileVisitor<Path> {
@Override
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) {
System.out.format("%s [Directory]%n", dir)
return CONTINUE
}
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
System.out.format("%s [File, Size: %s bytes]%n", file, attrs.size())
return CONTINUE
}
}
FileVisitor<Path> visitor = new DirVisitor<>()
return visitor
}
}
上面的代码生成以下结果。
[Directory]
.classpath [File, Size: 232 bytes]
.project [File, Size: 382 bytes]
.settings [Directory]
.settings\org.eclipse.core.resources.prefs [File, Size: 57 bytes]
bin [Directory]
bin\Main$1DirVisitor.class [File, Size: 1648 bytes]
bin\Main.class [File, Size: 1338 bytes]
destfile.txt [File, Size: 25 bytes]
luci3.txt [File, Size: 25 bytes]
my_second_file.txt [File, Size: 0 bytes]
person.ser [File, Size: 160 bytes]
personext.ser [File, Size: 93 bytes]
primitives.dat [File, Size: 42 bytes]
randomaccessfile.txt [File, Size: 18 bytes]
src [Directory]
src\Calculator.java [File, Size: 0 bytes]
src\Main.class [File, Size: 1111 bytes]
src\Main.java [File, Size: 1172 bytes]
stdout.txt [File, Size: 34 bytes]
test.txt [File, Size: 13 bytes]
ziptest.zip [File, Size: 22 bytes]
示例
以下代码显示如何使用FileVisitor
API删除目录树,把目录 C:\Java_Dev
和其中的所有内容删除。
import static java.nio.file.FileVisitResult.CONTINUE
import static java.nio.file.FileVisitResult.TERMINATE
import java.io.IOException
import java.nio.file.FileVisitResult
import java.nio.file.FileVisitor
import java.nio.file.Files
import java.nio.file.Path
import java.nio.file.Paths
import java.nio.file.SimpleFileVisitor
import java.nio.file.attribute.BasicFileAttributes
public class Main {
public static void main(String[] args) {
Path dirToDelete = Paths.get("C:\\Java_Dev")
FileVisitor<Path> visitor = getFileVisitor()
try {
Files.walkFileTree(dirToDelete, visitor)
} catch (IOException e) {
System.out.println(e.getMessage())
}
}
public static FileVisitor<Path> getFileVisitor() {
class DeleteDirVisitor extends SimpleFileVisitor<Path> {
@Override
public FileVisitResult postVisitDirectory(Path dir, IOException e) throws IOException {
FileVisitResult result = CONTINUE
if (e != null) {
System.out.format("Error deleting %s. %s%n", dir, e.getMessage())
result = TERMINATE
} else {
Files.delete(dir)
System.out.format("Deleted directory %s%n", dir)
}
return result
}
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
Files.delete(file)
System.out.format("Deleted file %s%n", file)
return CONTINUE
}
}
FileVisitor<Path> visitor = new DeleteDirVisitor()
return visitor
}
}
上面的代码生成以下结果。
Deleted file C:\Java_Dev\dir1\test1.txt
Deleted directory C:\Java_Dev\dir1
Deleted directory C:\Java_Dev\dir1 - 副本
Deleted file C:\Java_Dev\dir2\test1.txt
Deleted directory C:\Java_Dev\dir2
Deleted file C:\Java_Dev\test1.txt
Deleted file C:\Java_Dev\twinkle.txt
Deleted directory C:\Java_Dev
实例-2
以下代码显示如何使用walkFileTree()
方法跟随符号链接。
import java.nio.file.FileVisitOption
import java.nio.file.FileVisitor
import java.nio.file.Files
import java.nio.file.Path
import java.nio.file.Paths
import java.util.EnumSet
import java.util.Set
import static java.nio.file.FileVisitOption.FOLLOW_LINKS
public class Main {
public static void main(String[] args) throws Exception {
Path startDir = Paths.get("")
FileVisitor<Path> visitor = create your visitor
Set<FileVisitOption> options = EnumSet.of(FOLLOW_LINKS)
int depth = Integer.MAX_VALUE
Files.walkFileTree(startDir, options, depth, visitor)
}
}
模式匹配
可以使用glob
和正则表达式模式对字符串形式的Path
对象执行模式匹配。
功能接口PathMatcher
用于执行匹配。它包含一个matches(Path path)
方法,如果指定的路径匹配模式,则该方法返回true
。
模式字符串由两部分组成,语法和模式由冒号分隔:
syntax:pattern
语法的值是glob
或regex
。模式部分遵循取决于语法部分的值。glob
模式使用以下语法规则:
*
匹配零个或多个字符,而不会交叉目录边界。**
匹配零个或多个字符跨目录边界。?
只匹配一个字符。\
转义以下字符的特殊含义。\\
匹配单个反斜杠\*
匹配一个星号。
放在括号[]
中的字符称为括号表达式,它匹配单个字符。如:[aeiou]
将匹配a
,e
,i
,o
或u
。
两个字符之间的破折号指定范围。[a-z]
匹配a
和z
之间的所有字母。左括号后的感叹号(!
)被视为否定。 [!abc]
匹配除了a
,b
和c
之外的所有字符。
通过在大括号({}
)中指定逗号分隔的子模式来使用一组子模式。 例如,{txt,java,doc}
匹配txt
,java
和doc
。
路径的根组件的匹配是实现相关的。以下代码显示了如何使用PathMatcher
对象将路径与glob
模式匹配。
import java.nio.file.FileSystems
import java.nio.file.Path
import java.nio.file.PathMatcher
import java.nio.file.Paths
public class Main {
public static void main(String[] args) {
String globPattern = "glob:**txt"
PathMatcher matcher = FileSystems.getDefault().getPathMatcher(globPattern)
Path path = Paths.get("C:\\Java_Dev\\test1.txt")
boolean matched = matcher.matches(path)
System.out.format("%s matches %s: %b%n", globPattern, path, matched)
}
}
执行上面的代码,得到以下结果 -
glob:**txt matches C:\Java_Dev\test1.txt: true