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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 17:19:52  来源:igfitidea点击:

Java.nio: most concise recursive directory delete

javadirectoryniodelete-file

提问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 nioAPIs remove so much clutter and boilerplate...

考虑到新的nioAPI 消除了如此多的混乱和样板文件,这感觉非常笨拙和冗长……

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 below rootPathincluding
  • .sorted- sort the list in reverse order, so the directory itself comes after the including subdirectories and files
  • .map- map the Pathto File
  • .peek- is there only to show which entry is processed
  • .forEach- calls the .delete()method on every Fileobject
  • Files.walk- 返回以下所有文件/目录,rootPath包括
  • .sorted- 以相反的顺序对列表进行排序,因此目录本身位于包含子目录和文件之后
  • .map- 映射PathFile
  • .peek- 是否只显示处理了哪个条目
  • .forEach-.delete()在每个File对象上调用该方法

EDITAs first mentioned by @Sebyand now cited by @John Doughthe Files.walk()should be used in a try-with-resourceconstruct. 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-deletecontained the unpacked rt.jarof 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/barwould be deleted as well.

将遵循符号链接,该文件/tmp/dont_delete/bar也将被删除。

Using

使用

Files.walk(rootPath)

will not follow symlinks and the file /tmp/dont_delete/barwould 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);

Source:http://www.baeldung.com/java-delete-directory

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

回答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.deleteDirectoryfrom Apache Commons IOdeletes a directory recursively.

FileUtils.deleteDirectoryApache 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 中递归删除目录