文章首发于:clawhub.club


walkFileTree

NIO用来操作文件的API用起来是很舒服的,特别是这个walkFileTree静态方法:

1
2
3
4
public static Path walkFileTree(Path start,
Set<FileVisitOption> options,
int maxDepth,
FileVisitor<? super Path> visitor)
  • start
    开始的文件,也就是你要操作的文件夹
  • options
    配置遍历的选项,一般用EnumSet.of(FileVisitOption.FOLLOW_LINKS)遵循符号链接填充。
  • maxDepth
    迭代的最大深度
  • visitor
    要为每个文件调用的文件访问器,一般使用SimpleFileVisitor,因为可以任意实现自己想要使用的方法,其实现了FileVisitor接口。

这个方法的设计就是回调思想。

FileVisitor

FileVisitor接口中有四个方法:

preVisitDirectory

在访问目录中的项之前为目录调用。

visitFile

为目录中的文件调用。

visitFileFailed

为无法访问的文件调用。如果无法读取文件的属性、文件是无法打开的目录以及其他原因,则调用此方法。

postVisitDirectory

在访问了目录中的项及其所有子项之后,为目录调用。当目录的迭代提前完成时或者在遍历目录时调用I/O错误也会调用此方法。

FileVisitResult

此枚举类有四个选项:

  • CONTINUE:继续遍历
  • SKIP_SIBLINGS:继续遍历,但忽略当前节点的所有兄弟节点直接返回上一层继续遍历
  • SKIP_SUBTREE:继续遍历,但是忽略子目录,但是子文件还是会访问;
  • TERMINATE:终止遍历

应用

批量删除文件夹及其子文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/**
* Delete all file and folders.
*
* @param folder the folder
* @throws IOException the io exception
*/
public static void deleteAllFileAndFolders(Path folder) throws IOException {
Files.walkFileTree(folder, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
Files.delete(file);
return FileVisitResult.CONTINUE;
}

@Override
public FileVisitResult postVisitDirectory(Path dir, IOException e) throws IOException {
if (e == null) {
Files.deleteIfExists(dir);
return FileVisitResult.CONTINUE;
} else {
throw e;
}
}
});
}

统计文件夹下所有文件数量

迭代深度可以自由控制。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
 /**
* 统计指定文件夹下的子文件夹集合,不遍历子文件夹内部
*
* @param folder the folder
* @return the int
* @throws IOException the io exception
*/
public static Set<Path> findFolders(String folder) throws IOException {
Set<Path> folders = new HashSet<>();
Path path = Paths.get(folder);
Files.walkFileTree(path, EnumSet.of(FileVisitOption.FOLLOW_LINKS), 2, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) {
//访问目录前,计数
folders.add(dir);
// CONTINUE:继续遍历
// SKIP_SIBLINGS:继续遍历,但忽略当前节点的所有兄弟节点直接返回上一层继续遍历
// SKIP_SUBTREE:继续遍历,但是忽略子目录,但是子文件还是会访问;
// TERMINATE:终止遍历
return FileVisitResult.CONTINUE;
}
});
//除去自己
folders.remove(path);
return folders;
}