Java.nio:最简洁的递归目录删除
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/35988192/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Java.nio: most concise recursive directory delete
提问by fgysin reinstate Monica
I am currently trying to recursively delete a directory... Strangely enough the shortest piece of code I was able to find is the following construct, employing an ad-hoc inner classand in a visitor pattern...
我目前正在尝试递归删除一个目录......奇怪的是,我能找到的最短代码是以下构造,采用临时内部类和访问者模式......
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();
}
Source: here
来源:这里
This feels horribly clumsy and verbose, given that the new nio
APIs remove so much clutter and boilerplate...
考虑到新的nio
API 消除了如此多的混乱和样板文件,这感觉非常笨拙和冗长……
Is there any shorter way of achieving a forced, recursive directory delete?
有没有更短的方法来实现强制递归目录删除?
I'm looking for pure native Java 1.8 methods, so please don't link to external libraries...
我正在寻找纯原生 Java 1.8 方法,所以请不要链接到外部库...
采纳答案by SubOptimal
You can combine NIO 2 and the Stream API.
您可以结合使用 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
try (Stream<Path> walk = Files.walk(rootPath)) {
walk.sorted(Comparator.reverseOrder())
.map(Path::toFile)
.peek(System.out::println)
.forEach(File::delete);
}
Files.walk
- return all files/directories belowrootPath
including.sorted
- sort the list in reverse order, so the directory itself comes after the including subdirectories and files.map
- map thePath
toFile
.peek
- is there only to show which entry is processed.forEach
- calls the.delete()
method on everyFile
object
Files.walk
- 返回以下所有文件/目录,rootPath
包括.sorted
- 以相反的顺序对列表进行排序,因此目录本身位于包含子目录和文件之后.map
- 映射Path
到File
.peek
- 是否只显示处理了哪个条目.forEach
-.delete()
在每个File
对象上调用该方法
EDITAs first mentioned by @Sebyand now cited by @John Doughthe Files.walk()
should be used in a try-with-resource
construct. Thanks to both.
EDIT作为第一通过提及@Seby现在通过引用@约翰面团的Files.walk()
应该被用在try-with-resource
构建体。感谢双方。
From Files.walkjavadoc
从Files.walkjavadoc
If timely disposal of file system resources is required, the try-with-resources construct should be used to ensure that the stream's close method is invoked after the stream operations are completed.
如果需要及时处理文件系统资源,则应使用 try-with-resources 构造以确保在流操作完成后调用流的 close 方法。
EDIT
编辑
Here are some figures.
The directory /data/to-delete
contained the unpacked rt.jar
of jdk1.8.0_73 and a recent build of activemq.
这里有一些数字。
该目录/data/to-delete
包含解压后rt.jar
的 jdk1.8.0_73 和最新版本的activemq。
files: 36,427
dirs : 4,143
size : 514 MB
Times in milliseconds
以毫秒为单位的时间
int. SSD ext. USB3
NIO + Stream API 1,126 11,943
FileVisitor 1,362 13,561
Both version were executed without printing file names. The most limiting factor is the drive. Not the implementation.
两个版本都在不打印文件名的情况下执行。最大的限制因素是驱动器。不是执行。
EDIT
编辑
Some addtional information about tthe option FileVisitOption.FOLLOW_LINKS
.
关于选项的一些附加信息FileVisitOption.FOLLOW_LINKS
。
Assume following file and directory structure
假设以下文件和目录结构
/data/dont-delete/bar
/data/to-delete/foo
/data/to-delete/dont-delete -> ../dont-delete
Using
使用
Files.walk(rootPath, FileVisitOption.FOLLOW_LINKS)
will follow symlinks and the file /tmp/dont_delete/bar
would be deleted as well.
将遵循符号链接,该文件/tmp/dont_delete/bar
也将被删除。
Using
使用
Files.walk(rootPath)
will not follow symlinks and the file /tmp/dont_delete/bar
would not be deleted.
不会跟随符号链接,文件/tmp/dont_delete/bar
也不会被删除。
NOTE:Never use code as copy and paste without understanding what it does.
注意:在不了解代码的作用的情况下,切勿将代码用作复制和粘贴。
回答by asmaier
The following solution doesn't need the conversion from Path to File objects:
以下解决方案不需要从 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);
}
回答by bigspawn
If you must use only Java 7 with NIO
如果您必须仅将 Java 7 与 NIO 一起使用
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;
}
});
回答by justanother
If you already have Spring Core as part of your project, here is an easy way to do it:
如果您已经将 Spring Core 作为项目的一部分,这里有一个简单的方法:
FileSystemUtils.deleteRecursively(dir);
回答by user1122069
Files.walk(pathToBeDeleted).sorted(Comparator.reverseOrder()).forEach(Files::delete);
You'll need the "try with resources" pattern to close the stream if "timely disposal of file system resources is required".
如果“需要及时处理文件系统资源”,您将需要“尝试使用资源”模式来关闭流。
Also, probably an unwelcome comment, but it would be much cleaner and more readable to use a library. With the code in a shared function, it won't take up much space. Every person who looks at your code must validate that this code does a proper delete, and its by no means obvious.
此外,可能是一个不受欢迎的评论,但使用库会更清晰、更具可读性。使用共享函数中的代码,它不会占用太多空间。每个查看您代码的人都必须验证此代码是否进行了正确的删除,这绝不是显而易见的。
回答by Fernando Correia
FileUtils.deleteDirectory
from Apache Commons IOdeletes a directory recursively.
FileUtils.deleteDirectory
从Apache Commons IO递归删除目录。
Example:
例子:
Path pathToBeDeleted = TEMP_DIRECTORY.resolve(DIRECTORY_NAME);
boolean result = FileUtils.deleteDirectory(pathToBeDeleted.toFile());
For more information see Delete a Directory Recursively in Java.
有关详细信息,请参阅在 Java 中递归删除目录。