Does Files.createTempDirectory remove the directory after JVM exits normally?

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.

Leave a Comment

tech