Java.nio:最简洁的递归目录删除

fgy*_*ica 40 java directory nio delete-file

我目前正在尝试以递归方式删除目录...奇怪的是,我能够找到的最短的代码是以下构造,采用ad-hoc内部类访问者模式 ...

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();
}
Run Code Online (Sandbox Code Playgroud)

来源:这里

考虑到新的nioAPI消除了这么多的混乱和样板,这感觉非常笨拙和冗长......

有没有更短的方法来实现强制的递归目录删除?

我正在寻找纯本机Java 1.8方法,所以请不要链接到外部库...

Sub*_*mal 107

您可以将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);
}
Run Code Online (Sandbox Code Playgroud)
  • Files.walk- 返回下面的所有文件/目录,rootPath包括
  • .sorted - 以相反的顺序对列表进行排序,因此目录本身位于包含子目录和文件之后
  • .map- 映射PathFile
  • .peek - 是否只显示处理了哪个条目
  • .forEach- .delete()在每个File对象上调用方法

编辑

这是一些数字.
该目录Files.walk()包含解压缩try-with-resource的jdk1.8.0_73和最新版本的activemq.

files: 36,427
dirs :  4,143
size : 514 MB
Run Code Online (Sandbox Code Playgroud)

以毫秒为单位的时间

                    int. SSD     ext. USB3
NIO + Stream API    1,126        11,943
FileVisitor         1,362        13,561
Run Code Online (Sandbox Code Playgroud)

两个版本都在没有打印文件名的情况下执 最受限制因素是驱动器.不是实施.

编辑

关于选项的一些附加信息/data/to-delete.

假设以下文件和目录结构

/data/dont-delete/bar
/data/to-delete/foo
/data/to-delete/dont-delete -> ../dont-delete
Run Code Online (Sandbox Code Playgroud)

运用

Files.walk(rootPath, FileVisitOption.FOLLOW_LINKS)
Run Code Online (Sandbox Code Playgroud)

将遵循符号链接,文件rt.jar也将被删除.

运用

Files.walk(rootPath)
Run Code Online (Sandbox Code Playgroud)

不会遵循符号链接,FileVisitOption.FOLLOW_LINKS也不会删除该文件.

注意:切勿在不了解代码的情况下使用代码作为复制和粘贴.

  • 你不需要`.map(Path :: toFile)`; #.forEach`的arg可以是`Files.delete`. (6认同)
  • @pdxleif然后你需要在传递给`forEach(...)`的使用者函数中处理`Files.delete(Path p)`的`IOException`.而`file.delete()`不要抛出一个. (6认同)
  • 你为什么要添加`FileVisitOption.FOLLOW_LINKS`标志?这意味着您将清空符号链接指向的整个目标树. (3认同)

jus*_*her 14

如果您已经将 Spring Core 作为项目的一部分,这里有一个简单的方法:

FileSystemUtils.deleteRecursively(dir);
Run Code Online (Sandbox Code Playgroud)

来源:http : //www.baeldung.com/java-delete-directory


asm*_*ier 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);
}
Run Code Online (Sandbox Code Playgroud)


big*_*awn 5

如果您必须仅将 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;
  }
});
Run Code Online (Sandbox Code Playgroud)