我目前正在尝试以递归方式删除目录...奇怪的是,我能够找到的最短代码是以下构造,使用 ad-hoc内部类并在< em>访客模式 ...
Path rootPath = Paths.get("data/to-delete");
try {
Files.walkFileTree(rootPath, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
System.out.println("delete file: " + file.toString());
Files.delete(file);
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
Files.delete(dir);
System.out.println("delete dir: " + dir.toString());
return FileVisitResult.CONTINUE;
}
});
} catch(IOException e){
e.printStackTrace();
}
来源:here
考虑到新的nio
API消除了这么多的混乱和样板,这感觉非常笨拙和冗长......
有没有更短的方法来实现强制的递归目录删除?
我正在寻找纯本机Java 1.8方法,所以请不要链接到外部库...
答案 0 :(得分:101)
您可以将NIO 2和Stream API结合使用。
Path rootPath = Paths.get("/data/to-delete");
// before you copy and paste the snippet
// - read the post till the end
// - read the javadoc to understand what the code will do
//
// a) to follow softlinks (removes the linked file too) use
// Files.walk(rootPath, FileVisitOption.FOLLOW_LINKS)
//
// b) to not follow softlinks (removes only the softlink) use
// the snippet below
Files.walk(rootPath)
.sorted(Comparator.reverseOrder())
.map(Path::toFile)
.peek(System.out::println)
.forEach(File::delete);
Files.walk
- 返回rootPath
下面的所有文件/目录,包括.sorted
- 按相反顺序对列表进行排序,因此目录本身位于包含子目录和文件之后.map
- 将Path
映射到File
.peek
- 只显示处理了哪个条目.forEach
- 在每个.delete()
对象上调用File
方法编辑
以下是一些数字
目录/data/to-delete
包含解压缩的rt.jar
jdk1.8.0_73和最近版本的activemq。
files: 36,427
dirs : 4,143
size : 514 MB
以毫秒为单位的时间
int. SSD ext. USB3
NIO + Stream API 1,126 11,943
FileVisitor 1,362 13,561
两个版本都在没有打印文件名的情况下执行。最受限制因素是驱动器。不是实施。
编辑
有关选项FileVisitOption.FOLLOW_LINKS
的一些附加信息。
假设以下文件和目录结构
/data/dont-delete/bar
/data/to-delete/foo
/data/to-delete/dont-delete -> ../dont-delete
使用
Files.walk(rootPath, FileVisitOption.FOLLOW_LINKS)
将遵循符号链接,文件/tmp/dont_delete/bar
也将被删除。
使用
Files.walk(rootPath)
不会遵循符号链接,文件/tmp/dont_delete/bar
也不会被删除。
注意:切勿在不了解代码的情况下使用代码进行复制和粘贴。
答案 1 :(得分:5)
以下解决方案不需要从Path到File对象的转换:
Path rootPath = Paths.get("/data/to-delete");
final List<Path> pathsToDelete = Files.walk(rootPath).sorted(Comparator.reverseOrder()).collect(Collectors.toList());
for(Path path : pathsToDelete) {
Files.deleteIfExists(path);
}
答案 2 :(得分:3)
如果必须仅使用带有NIO的Java 7
Path path = Paths.get("./target/logs");
Files.walkFileTree(path, 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 exc)
throws IOException {
Files.delete(dir);
return FileVisitResult.CONTINUE;
}
});
答案 3 :(得分:2)
如果你已经将Spring Core作为项目的一部分,这是一个简单的方法:
FileSystemUtils.deleteRecursively(file);
答案 4 :(得分:1)
Files.walk(pathToBeDeleted).sorted(Comparator.reverseOrder()).forEach(Files::delete);
如果“需要及时处理文件系统资源”,您将需要“尝试使用资源”模式来关闭流。
此外,可能是一个不受欢迎的评论,但使用库会更清晰,更易读。使用共享函数中的代码,它不会占用太多空间。每个查看代码的人都必须验证此代码是否正确删除,而且它并不明显。
答案 5 :(得分:0)
FileUtils.deleteDirectory
递归删除目录。
示例:
Path pathToBeDeleted = TEMP_DIRECTORY.resolve(DIRECTORY_NAME);
boolean result = FileUtils.deleteDirectory(pathToBeDeleted.toFile());
有关更多信息,请参见Delete a Directory Recursively in Java。