在很多时候都会遇到删除一个不为空的文件夹的情景,在不使用Files类时,可以使用递归的方式
来删除,但递归的代码不是很容易理解,看起来也不够优雅。于是用Files
这个类来操作,代码就变得优雅起来了。
先上一段传统的代码来遍历一个不为空的文件夹,因为用代码来操作文件是十分危险的一个操作,删除文件很有可能就无法恢复,所以先来遍历一下。
FileOperation.java
import java.io.File;
import java.io.IOException;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.concurrent.atomic.AtomicInteger;
public class FileOperation {
public static void main(String[] args) throws IOException {
m1();//传统递归遍历
}
private static void m1() {
AtomicInteger dirCount = new AtomicInteger();
AtomicInteger fileCount = new AtomicInteger();
printFileAndDir(new File("C:\\Program Files\\Java\\jdk1.8.0_131"),dirCount,fileCount);
System.out.println(dirCount.get());
System.out.println(fileCount.get());
}
private static void printFileAndDir(File root, AtomicInteger dirCount, AtomicInteger fileCount){
for (File file : root.listFiles()) {
if (file.isDirectory()){
dirCount.incrementAndGet();
System.out.println("====>" + file);
printFileAndDir(file,dirCount,fileCount);
}else {
fileCount.incrementAndGet();
System.out.println("---->" + file);
}
}
}
}
代码中的AtomicInteger
可以看做成一个计数器,这里不使用简单的int count
作为计数器的原因是,在后续代码中的操作是会在一个内部类中的,所以int count
这样的计数器则无效,AtomicInteger对象的incrementAndGet()
方法可以理解为计数器+1。(这里不用太过计较这个类)
这样的递归代码可能不是很容易理解的,下面就放上Files类操作的代码
TestFilesWalkFileTree .java
import java.io.File;
import java.io.IOException;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.concurrent.atomic.AtomicInteger;
public class TestFilesWalkFileTree {
public static void main(String[] args) throws IOException {
m1();//遍历目录下的文件和文件夹
}
private static void m1() throws IOException {
AtomicInteger dirCount = new AtomicInteger();
AtomicInteger fileCount = new AtomicInteger();
Files.walkFileTree(Paths.get("C:\\Program Files\\Java\\jdk1.8.0_131"),new SimpleFileVisitor<Path>(){
@Override
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
System.out.println("======>" + dir);
dirCount.incrementAndGet();
return super.preVisitDirectory(dir, attrs);
}
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
System.out.println("----->" + file);
fileCount.incrementAndGet();
return super.visitFile(file, attrs);
}
});
System.out.println(dirCount.get());
System.out.println(fileCount.get());
}
}
解释一下这块代码块:
Files.walkFileTree(
Paths.get("C:\\Program Files\\Java\\jdk1.8.0_131"),
new SimpleFileVisitor<Path>(){}
);
这个 Files.walkFileTree(Path start, FileVisitor<? super Path> visitor);
静态方法的参数传递两个。
一个是Path类,用于指向要被操作的文件夹,
另一个是一个FileVisitor,此处是一个观察者模式的设计,
new SimpleFileVisitor<Path>(){}
,这样弄一个内部类就行,重写这个内部类的一些方法,来操作文件夹。
重写这四个方法即可,不一定要全部重写
- preVisitDirectory:访问文件夹之前的操作
- visitFile:访问文件时,对文件的操作
- visitFileFailed:访问文件失败时,进行一些处理
- postVisitDirectory:访问完文件夹之后的操作
有一点要强调的就是,重写这些方法时不要对return进行修改
,否则文件夹无法遍历下去
用Files.walkFileTree这个方法来遍历文件夹下的文件夹和文件,这样的代码看过去更容易理解,也更加优雅。
最后附上删除文件夹的代码(也称之为删库跑路代码,hhh)
TestFilesWalkFileTree .java
package com.sixteen.netty;
import java.io.File;
import java.io.IOException;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.concurrent.atomic.AtomicInteger;
public class TestFilesWalkFileTree {
public static void main(String[] args) throws IOException {
m4();//删除文件夹
}
private static void m4() throws IOException {
Files.walkFileTree(Paths.get("E:\\html5 - 副本"),new SimpleFileVisitor<Path>(){
@Override
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
System.out.println("===> 进入" + dir);
return super.preVisitDirectory(dir, attrs);
}
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
System.out.println(file);
Files.delete(file);
return super.visitFile(file, attrs);
}
@Override
public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
System.out.println("<=== 退出" + dir);
Files.delete(dir);
return super.postVisitDirectory(dir, exc);
}
});
}
}
解释一下删除文件夹的代码,分为以下几个步骤:
- 先判断本身一个文件夹还是文件,如果是文件夹,则先进入
preVisitDirectory方法
,此处无需对文件夹做出什么操作,可以打印一下信息 - 当判断为是文件时,进入
visitFile方法
,此时就可以直接对文件进行操作,此处是删除文件 - 当把一个文件夹内的文件都访问过后,要退出这个文件夹时,进入
postVisitDirectory方法
,由于是文件时会被第2步操作删除文件夹,所以此时的文件夹为空,可以直接删除,这样就把一个文件夹给删除了
如果文件夹内含文件和文件夹,文件夹中的文件夹会重复1~3的步骤,也就是递归,只不过这样写出的代码更加优雅更加容易理解(当然是对比递归而言)。
以上就是Files类walkFileTree方法的一些解释,如有错误,还望大佬们指出。