[疯狂Java]NIO.2:walkFileTree、FileVisitor(遍历文件/目录)

时间:2021-06-03 11:56:05

1. 遍历文件和目录——FileVisitor:

    1) 在旧版本中遍历文件系统只能通过递归的方法来实现,但是这种方法不仅消耗资源大而且效率低;

    2) NIO.2的Files工具类提供了一个静态工具方法walkFileTree来高效并优雅地遍历文件系统;

    3) walkFileTree:

         i. 原型:static Path Files.walkFileTree(Path start, FileVisitor<? super Path> visitor);

         ii. 表示从start代表的节点开始遍历文件系统;

         iii. 其中visitor是遍历过程中的行为控制器;

    4) 遍历行为控制器——FileVisitor:

         i. 它是一个接口,里面定义了4个方法用来指定当你访问一个节点之前、之中、之后、失败时应该采取什么行动;

         ii. 这个设计非常优雅和科学,毕竟你在遍历文件系统时想要做的事情无外乎发生在这几个时间点上,Java全部为你考虑好了,并搭好了框架!多么的贴心!!

         iii. API:

public interface FileVisitor<T> {

FileVisitResult preVisitDirectory(T dir, BasicFileAttributes attrs) // 访问一个目录前要干啥
throws IOException;

FileVisitResult postVisitDirectory(T dir, IOException exc) // 访问一个目录后要干啥
throws IOException;

FileVisitResult visitFile(T file, BasicFileAttributes attrs) // 正在访问一个文件时要干啥
throws IOException;

FileVisitResult visitFileFailed(T file, IOException exc) // 访问一个文件失败时要干啥
throws IOException;
}
!!注意,里面的文件和目录要区别开;

!可以看到它是一个模板接口,但是在walkFileTree中它的类型已经确定了就是Path,因此里面的T类型就是Path类型了;

        iv. 接口方法的返回值FileVisitResult是一个枚举类型,walkFileTree就是会根据这个返回值决定是否要继续遍历下去,如果要继续遍历则应该怎样遍历,它总共有4个枚举值:都是FileVisitResult中定义的枚举值

CONTINUE:继续遍历

SKIP_SIBLINGS:继续遍历,但忽略当前节点的所有兄弟节点直接返回上一层继续遍历

SKIP_SUBTREE:继续遍历,但是忽略子目录,但是子文件还是会访问;

TERMINATE:终止遍历

    5) 实际使用中通常直接继承FileVisitor的适配器SimpleFileVisitor,因为只需要实现你感兴趣的方法即可,无需4个方法全部都实现;

    6) 示例:

public class Test {

public static void main(String[] args) throws IOException {

Files.walkFileTree(Paths.get(".."), new SimpleFileVisitor<Path>() {

@Override
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
// TODO Auto-generated method stub
// return super.preVisitDirectory(dir, attrs);
System.out.println("正在访问:" + dir + "目录");
return FileVisitResult.CONTINUE;
}

@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
// TODO Auto-generated method stub
// return super.visitFile(file, attrs);
System.out.println("\t正在访问" + file + "文件");
if (file.endsWith("Test.java")) {
System.out.println("******找到目标文件Test.java******");
return FileVisitResult.TERMINATE; // 找到了就终止
}
return FileVisitResult.CONTINUE; // 没找到继续找
}

});
}
}
!!Path可以像String那样进行字符串校验,校验路径中的字符串:都是Path的对象方法

        a. boolean startsWith(String other); // 前缀检查

        b. boolean startsWith(Path other);

        c. boolean endsWith(String other); // 后缀检查

        d. boolean endsWith(Path other);

!!比较的都是其path成员字符串里的内容,并不会深入文件系统用完整的绝对路径来比较