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

2022-08-31 16:16:38

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

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

来源: 这里

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

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

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


答案 1

您可以将 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- 映射到PathFile
  • .peek- 只是为了显示正在处理的条目
  • .forEach- 在每个对象上调用方法.delete()File

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

From Files.walk javadoc

如果需要及时处置文件系统资源,则应使用资源试用构造来确保在流操作完成后调用流的 close 方法。

编辑

以下是一些数字。
该目录包含解压缩的jdk1.8.0_73和最近构建的 activemq/data/to-deletert.jar

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

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


答案 2

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

FileSystemUtils.deleteRecursively(dir);

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


推荐