42

Does Files.createTempDirectory remove the directory after JVM exits normally? Or do I need to manually recursively remove the temporary directory content?

Subhrajyoti Majumder
  • 40,646
  • 13
  • 77
  • 103

6 Answers6

64

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.

JohnK
  • 6,865
  • 8
  • 49
  • 75
dimo414
  • 47,227
  • 18
  • 148
  • 244
  • 10
    In Spring there's a helper method `org.springframework.util.FileSystemUtils.deleteRecursively(File root)` for explicit recursive directory deletion. – Sergey Shcherbakov Jun 21 '17 at 06:48
28

As per the API, no it doesn't, you need to manually remove the directory, using file.deleteOnExit() method.

As with the createTempFile methods, this method is only part of a temporary-file facility. A shutdown-hook, or the File.deleteOnExit() mechanism may be used to delete the directory automatically.

Guillaume Massé
  • 8,004
  • 8
  • 44
  • 57
Pradeep Simha
  • 17,683
  • 18
  • 56
  • 107
  • Like will this work? `new File(Files.createTempDirectory(null).toString()).deleteOnExit()` –  Feb 22 '13 at 10:45
  • 2
    @HowardGuo, I don't think so, you are passing null to createTempDirectory method – Pradeep Simha Feb 22 '13 at 10:49
  • 2
    @HowardGuo, http://docs.oracle.com/javase/tutorial/essential/io/dirs.html this should give you more information – Pradeep Simha Feb 22 '13 at 10:51
  • 1
    I thought the document says that `prefix` parameter may be given null –  Feb 22 '13 at 10:51
  • 1
    @HowardGuo, no it cannot be :) In the link you can refer example program – Pradeep Simha Feb 22 '13 at 10:55
  • 1
    Am i missing anything here? I thought I read: `prefix - the prefix string to be used in generating the directory's name; may be null` –  Feb 22 '13 at 10:57
  • 1
    @HowardGuo, yes prefix maybe null, but not others. If you read API docs, this method accepts 3 arguments and your code won't compile since you are passing only 1 argument – Pradeep Simha Feb 22 '13 at 11:00
  • Thanks. I just tried this piece of code: `val dir = Files.createTempDirectory(null); new File(dir.toString()).deleteOnExit()` it creates the temp directory but does not delete it after JVM exists. guess I have to find another way to delete the dir.. –  Feb 22 '13 at 11:03
  • 4
    @PradeepSimha - what makes you say you can't pass `null`? You certainly can call [`Files.createTempDirectory(null)`](http://docs.oracle.com/javase/7/docs/api/java/nio/file/Files.html#createTempDirectory(java.lang.String,%20java.nio.file.attribute.FileAttribute...)), this works exactly as one would expect - it creates a new arbitrarily named directory and returns its Path. – dimo414 Nov 29 '13 at 08:15
24

You can add apache commons io dependency to your project and then use FileUtils.deleteDirectory() to do something like:

Runtime.getRuntime().addShutdownHook(new Thread() {
    @Override
    public void run() {
        try {
            FileUtils.deleteDirectory(tmp_dir_path.toFile());
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }
});

For more information about apache commons check: https://commons.apache.org/proper/commons-io/

SiKing
  • 10,003
  • 10
  • 39
  • 90
Yahya
  • 321
  • 3
  • 3
2

No it doesn't - createTempDirectory

As with the createTempFile methods, this method is only part of a temporary-file facility. A shutdown-hook, or the File.deleteOnExit() mechanism may be used to delete the directory automatically.

1

No, it doesn't. You have to do it on your own. Or use java.io.File.deleteOnExit() but I guess it doesn't work for non-empty directories

Adam Dyga
  • 8,666
  • 4
  • 27
  • 35
  • 3
    I would love Java more if `new File(Files.createTempDirectory(null).toString()).deleteOnExit()` works, hahaha.. –  Feb 22 '13 at 10:44
  • 4
    It works exactly as documented - "the directory must be empty in order to be deleted" - wanting to delete a non-empty directory is reasonable, but don't confuse your desire with "Java doesn't work". – dimo414 Nov 29 '13 at 07:48
0

If using JUnit 5, the @TempDir annotation is super nice. It also recursively deletes the created directory when the test or test-class ends (depending on the scope of the annotation).

For example:

@BeforeAll
public static void setup(@TempDir Path tempDir) {
    // The dir will be deleted when the class ends, ala @AfterClass
}

Or

@Test
public static void myTest(@TempDir Path tempDir) {
    // The dir will be deleted when this test method ends
}

See: https://www.baeldung.com/junit-5-temporary-directory

jsims
  • 1
  • 1