Temporary directories created by Files.createTempDirectory()
are not deleted upon system exit (JVM termination), unless you configure them to do so:
A shutdown-hook, or the
File.deleteOnExit()
mechanism may be used to delete the directory automatically.
Meaning you could call:
Path tmp = Files.createTempDirectory(null);
tmp.toFile().deleteOnExit();
However you cannot delete a directory unless it’s empty, as document by File.delete()
:
Deletes the file or directory denoted by this abstract pathname. If
this pathname denotes a directory, then the directory must be empty in
order to be deleted.
So we need to get a bit fancier if you want the directory and its contents deleted. You can recursively register a directory and its children for deletion like so:
public static void recursiveDeleteOnExit(Path path) throws IOException {
Files.walkFileTree(path, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(Path file,
@SuppressWarnings("unused") BasicFileAttributes attrs) {
file.toFile().deleteOnExit();
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult preVisitDirectory(Path dir,
@SuppressWarnings("unused") BasicFileAttributes attrs) {
dir.toFile().deleteOnExit();
return FileVisitResult.CONTINUE;
}
});
}
Take note however, this registers all currently existing files for deletion – if after calling this method you create new files, they and their parent directories will not be deleted per the documented behavior of File.delete()
.
If you want to delete a directory upon exit, regardless of the contents of said directory, you can use a shutdown-hook in an almost identical manner:
public static void recursiveDeleteOnShutdownHook(final Path path) {
Runtime.getRuntime().addShutdownHook(new Thread(
new Runnable() {
@Override
public void run() {
try {
Files.walkFileTree(path, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(Path file,
@SuppressWarnings("unused") BasicFileAttributes attrs)
throws IOException {
Files.delete(file);
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult postVisitDirectory(Path dir, IOException e)
throws IOException {
if (e == null) {
Files.delete(dir);
return FileVisitResult.CONTINUE;
}
// directory iteration failed
throw e;
}
});
} catch (IOException e) {
throw new RuntimeException("Failed to delete "+path, e);
}
}}));
}
Note however that calling this repeatedly registers a new shutdown thread each time, which could potentially cause problems at scale. File.deleteOnExit()
stores a set of registered files, and deletes all of them in one shutdown hook. If you need to delete many directories in this manner, you’d want to implement something similar.