Java.nio: most concise recursive directory delete

前端 未结 6 862
日久生厌
日久生厌 2020-12-13 06:10

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

相关标签:
6条回答
  • 2020-12-13 06:48

    You can combine NIO 2 and the 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 rootPath including
    • .sorted - sort the list in reverse order, so the directory itself comes after the including subdirectories and files
    • .map - map the Path to File
    • .peek - is there only to show which entry is processed
    • .forEach - calls the .delete() method on every File object

    EDIT As first mentioned by @Seby and now cited by @John Dough the Files.walk() should be used in a try-with-resource construct. Thanks to both.

    From Files.walk javadoc

    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.

    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.

    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.

    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.

    Using

    Files.walk(rootPath)
    

    will not follow symlinks and the file /tmp/dont_delete/bar would not be deleted.

    NOTE: Never use code as copy and paste without understanding what it does.

    0 讨论(0)
  • 2020-12-13 06:50

    If you already have Spring Core as part of your project, here is an easy way to do it:

    FileSystemUtils.deleteRecursively(dir);
    

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

    0 讨论(0)
  • 2020-12-13 06:54

    If you must use only Java 7 with 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;
      }
    });
    
    0 讨论(0)
  • 2020-12-13 06:58

    FileUtils.deleteDirectory from Apache Commons IO deletes a directory recursively.

    Example:

    Path pathToBeDeleted = TEMP_DIRECTORY.resolve(DIRECTORY_NAME);
    
    boolean result = FileUtils.deleteDirectory(pathToBeDeleted.toFile());
    

    For more information see Delete a Directory Recursively in Java.

    0 讨论(0)
  • 2020-12-13 07:05

    The following solution doesn't need the conversion from Path to File objects:

    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);
    }
    
    0 讨论(0)
  • 2020-12-13 07:07
    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.

    0 讨论(0)
提交回复
热议问题