fgysin fgysin - 17 days ago 7
Java Question

Java.nio: most concise recursive directory delete

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 class and 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
nio
APIs remove so much clutter and boilerplate...

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...

Answer

You can combine NIO 2 and the Stream API.

Path rootPath = Paths.get("/data/to-delete");
Files.walk(rootPath, FileVisitOption.FOLLOW_LINKS)
    .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 - path the Path to File
  • .peek - is there only to show which entry is processed
  • .forEach - calls an every File object the .delete() method

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.