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

新手上路,请多包涵

我目前正在尝试递归地删除一个目录……奇怪的是,我能找到的最短代码是以下结构,采用 临时内部类访问者模式……

 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();
}

资料来源: 这里

鉴于新的 nio API 消除了如此多的混乱和样板,这感觉非常笨拙和冗长……

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

我正在寻找纯原生 Java 1.8 方法,所以请不要链接到外部库…

原文由 fgysin 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 457
2 个回答

您可以结合使用 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 - 返回下面的所有文件/目录 rootPath 包括
  • .sorted - 以相反的顺序对列表进行排序,因此目录本身位于包括子目录和文件之后
  • .map - 将 Path 映射到 File
  • .peek - 仅显示处理了哪个条目
  • .forEach - 在每个 File 对象上调用 .delete() 方法

编辑 正如 @Seby 首次提到的,现在被@John Dough 引用, Files.walk() 应该在 try-with-resource 构造中使用。感谢两者。

来自 Files.walk javadoc

如果需要及时处理文件系统资源,应该使用 try-with-resources 结构来确保在流操作完成后调用流的 close 方法。

编辑

这里有一些数字。

目录 /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 也不会被删除。

注意: 切勿在不了解代码功能的情况下将代码用作复制和粘贴。

原文由 SubOptimal 发布,翻译遵循 CC BY-SA 4.0 许可协议

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

 FileSystemUtils.deleteRecursively(dir);

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

原文由 justanother 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题