How to create a temporary directory/folder in Java?

JavaFileFile IoDirectoryTemporary Directory

Java Problem Overview


Is there a standard and reliable way of creating a temporary directory inside a Java application? There's an entry in Java's issue database, which has a bit of code in the comments, but I wonder if there is a standard solution to be found in one of the usual libraries (Apache Commons etc.) ?

Java Solutions


Solution 1 - Java

If you are using JDK 7 use the new Files.createTempDirectory class to create the temporary directory.

Path tempDirWithPrefix = Files.createTempDirectory(prefix);

Before JDK 7 this should do it:

public static File createTempDirectory()
    throws IOException
{
    final File temp;
    
    temp = File.createTempFile("temp", Long.toString(System.nanoTime()));
    
    if(!(temp.delete()))
    {
        throw new IOException("Could not delete temp file: " + temp.getAbsolutePath());
    }
    
    if(!(temp.mkdir()))
    {
        throw new IOException("Could not create temp directory: " + temp.getAbsolutePath());
    }
    
    return (temp);
}

You could make better exceptions (subclass IOException) if you want.

Solution 2 - Java

The Google Guava library has a ton of helpful utilities. One of note here is the Files class. It has a bunch of useful methods including:

File myTempDir = Files.createTempDir();

This does exactly what you asked for in one line. If you read the documentation here you'll see that the proposed adaptation of File.createTempFile("install", "dir") typically introduces security vulnerabilities.

Solution 3 - Java

If you need a temporary directory for testing and you are using jUnit, @Rule together with TemporaryFolder solves your problem:

@Rule
public TemporaryFolder folder = new TemporaryFolder();

From the documentation:

> The TemporaryFolder Rule allows creation of files and folders that are guaranteed to be deleted when the test method finishes (whether it passes or fails)


Update:

If you are using JUnit Jupiter (version 5.1.1 or greater), you have the option to use JUnit Pioneer which is the JUnit 5 Extension Pack.

Copied from the project documentation:

> For example, the following test registers the extension for a single test method, creates and writes a file to the temporary directory and checks its content.

@Test
@ExtendWith(TempDirectory.class)
void test(@TempDir Path tempDir) {
    Path file = tempDir.resolve("test.txt");
    writeFile(file);
    assertExpectedFileContent(file);
}

More info in the JavaDoc and the JavaDoc of TempDirectory

Gradle:

dependencies {
    testImplementation 'org.junit-pioneer:junit-pioneer:0.1.2'
}

Maven:

<dependency>
   <groupId>org.junit-pioneer</groupId>
   <artifactId>junit-pioneer</artifactId>
   <version>0.1.2</version>
   <scope>test</scope>
</dependency>

Update 2:

The @TempDir annotation was added to the JUnit Jupiter 5.4.0 release as an experimental feature. Example copied from the JUnit 5 User Guide:

@Test
void writeItemsToFile(@TempDir Path tempDir) throws IOException {
    Path file = tempDir.resolve("test.txt");

    new ListWriter(file).write("a", "b", "c");

    assertEquals(singletonList("a,b,c"), Files.readAllLines(file));
}

Solution 4 - Java

Naively written code to solve this problem suffers from race conditions, including several of the answers here. Historically you could think carefully about race conditions and write it yourself, or you could use a third-party library like Google's Guava (as Spina's answer suggested.) Or you could write buggy code.

But as of JDK 7, there is good news! The Java standard library itself now provides a properly working (non-racy) solution to this problem. You want java.nio.file.Files#createTempDirectory(). From the documentation:

public static Path createTempDirectory(Path dir,
                       String prefix,
                       FileAttribute<?>... attrs)
                                throws IOException

> Creates a new directory in the specified directory, using the given prefix to generate its name. The resulting Path is associated with the same FileSystem as the given directory.

> The details as to how the name of the directory is constructed is implementation dependent and therefore not specified. Where possible the prefix is used to construct candidate names.

This effectively resolves the embarrassingly ancient bug report in the Sun bug tracker which asked for just such a function.

Solution 5 - Java

This is the source code to the Guava library's Files.createTempDir(). It's nowhere as complex as you might think:

public static File createTempDir() {
  File baseDir = new File(System.getProperty("java.io.tmpdir"));
  String baseName = System.currentTimeMillis() + "-";

  for (int counter = 0; counter < TEMP_DIR_ATTEMPTS; counter++) {
    File tempDir = new File(baseDir, baseName + counter);
    if (tempDir.mkdir()) {
      return tempDir;
    }
  }
  throw new IllegalStateException("Failed to create directory within "
      + TEMP_DIR_ATTEMPTS + " attempts (tried "
      + baseName + "0 to " + baseName + (TEMP_DIR_ATTEMPTS - 1) + ')');
}

By default:

private static final int TEMP_DIR_ATTEMPTS = 10000;

See here

Solution 6 - Java

Do not use deleteOnExit() even if you explicitly delete it later.

Google 'deleteonexit is evil' for more info, but the gist of the problem is:

  1. deleteOnExit() only deletes for normal JVM shutdowns, not crashes or killing the JVM process.

  2. deleteOnExit() only deletes on JVM shutdown - not good for long running server processes because:

  3. The most evil of all - deleteOnExit() consumes memory for each temp file entry. If your process is running for months, or creates a lot of temp files in a short time, you consume memory and never release it until the JVM shuts down.

Solution 7 - Java

As of Java 1.7 createTempDirectory(prefix, attrs) and createTempDirectory(dir, prefix, attrs) are included in java.nio.file.Files

Example: File tempDir = Files.createTempDirectory("foobar").toFile();

Solution 8 - Java

This is what I decided to do for my own code:

/**
 * Create a new temporary directory. Use something like
 * {@link #recursiveDelete(File)} to clean this directory up since it isn't
 * deleted automatically
 * @return  the new directory
 * @throws IOException if there is an error creating the temporary directory
 */
public static File createTempDir() throws IOException
{
    final File sysTempDir = new File(System.getProperty("java.io.tmpdir"));
    File newTempDir;
    final int maxAttempts = 9;
    int attemptCount = 0;
    do
    {
        attemptCount++;
        if(attemptCount > maxAttempts)
        {
            throw new IOException(
                    "The highly improbable has occurred! Failed to " +
                    "create a unique temporary directory after " +
                    maxAttempts + " attempts.");
        }
        String dirName = UUID.randomUUID().toString();
        newTempDir = new File(sysTempDir, dirName);
    } while(newTempDir.exists());
    
    if(newTempDir.mkdirs())
    {
        return newTempDir;
    }
    else
    {
        throw new IOException(
                "Failed to create temp dir named " +
                newTempDir.getAbsolutePath());
    }
}

/**
 * Recursively delete file or directory
 * @param fileOrDir
 *          the file or dir to delete
 * @return
 *          true iff all files are successfully deleted
 */
public static boolean recursiveDelete(File fileOrDir)
{
    if(fileOrDir.isDirectory())
    {
        // recursively delete contents
        for(File innerFile: fileOrDir.listFiles())
        {
            if(!FileUtilities.recursiveDelete(innerFile))
            {
                return false;
            }
        }
    }
    
    return fileOrDir.delete();
}

Solution 9 - Java

Well, "createTempFile" actually creates the file. So why not just delete it first, and then do the mkdir on it?

Solution 10 - Java

As discussed in this RFE and its comments, you could call tempDir.delete() first. Or you could use System.getProperty("java.io.tmpdir") and create a directory there. Either way, you should remember to call tempDir.deleteOnExit(), or the file won't be deleted after you're done.

Solution 11 - Java

This code should work reasonably well:

public static File createTempDir() {
    final String baseTempPath = System.getProperty("java.io.tmpdir");

    Random rand = new Random();
    int randomInt = 1 + rand.nextInt();
    
    File tempDir = new File(baseTempPath + File.separator + "tempDir" + randomInt);
    if (tempDir.exists() == false) {
        tempDir.mkdir();
    }

    tempDir.deleteOnExit();
    
    return tempDir;
}

Solution 12 - Java

Just for completion, this is the code from google guava library. It is not my code, but I think it is valueable to show it here in this thread.

  /** Maximum loop count when creating temp directories. */
  private static final int TEMP_DIR_ATTEMPTS = 10000;

  /**
   * Atomically creates a new directory somewhere beneath the system's temporary directory (as
   * defined by the {@code java.io.tmpdir} system property), and returns its name.
   *
   * <p>Use this method instead of {@link File#createTempFile(String, String)} when you wish to
   * create a directory, not a regular file. A common pitfall is to call {@code createTempFile},
   * delete the file and create a directory in its place, but this leads a race condition which can
   * be exploited to create security vulnerabilities, especially when executable files are to be
   * written into the directory.
   *
   * <p>This method assumes that the temporary volume is writable, has free inodes and free blocks,
   * and that it will not be called thousands of times per second.
   *
   * @return the newly-created directory
   * @throws IllegalStateException if the directory could not be created
   */
  public static File createTempDir() {
    File baseDir = new File(System.getProperty("java.io.tmpdir"));
    String baseName = System.currentTimeMillis() + "-";

    for (int counter = 0; counter < TEMP_DIR_ATTEMPTS; counter++) {
      File tempDir = new File(baseDir, baseName + counter);
      if (tempDir.mkdir()) {
        return tempDir;
      }
    }
    throw new IllegalStateException(
        "Failed to create directory within "
            + TEMP_DIR_ATTEMPTS
            + " attempts (tried "
            + baseName
            + "0 to "
            + baseName
            + (TEMP_DIR_ATTEMPTS - 1)
            + ')');
  }

Solution 13 - Java

I got the same problem so this is just another answer for those who are interested, and it's similar to one of the above:

public static final String tempDir = System.getProperty("java.io.tmpdir")+"tmp"+System.nanoTime();
static {
    File f = new File(tempDir);
    if(!f.exists())
        f.mkdir();
}

And for my application, I decided that to add in a option to clear the temp on exit so I added in a shut-down hook:

Runtime.getRuntime().addShutdownHook(new Thread() {
        @Override
        public void run() {
            //stackless deletion
            String root = MainWindow.tempDir;
            Stack<String> dirStack = new Stack<String>();
            dirStack.push(root);
            while(!dirStack.empty()) {
                String dir = dirStack.pop();
                File f = new File(dir);
                if(f.listFiles().length==0)
                    f.delete();
                else {
                    dirStack.push(dir);
                    for(File ff: f.listFiles()) {
                        if(ff.isFile())
                            ff.delete();
                        else if(ff.isDirectory())
                            dirStack.push(ff.getPath());
                    }
                }
            }
        }
    });

The method delete all subdirs and files before deleting the temp, without using the callstack (which is totally optional and you could do it with recursion at this point), but I want to be on the safe side.

Solution 14 - Java

As you can see in the other answers, no standard approach has arisen. Hence you already mentioned Apache Commons, I propose the following approach using FileUtils from Apache Commons IO:

/**
 * Creates a temporary subdirectory in the standard temporary directory.
 * This will be automatically deleted upon exit.
 * 
 * @param prefix
 *            the prefix used to create the directory, completed by a
 *            current timestamp. Use for instance your application's name
 * @return the directory
 */
public static File createTempDirectory(String prefix) {

	final File tmp = new File(FileUtils.getTempDirectory().getAbsolutePath()
			+ "/" + prefix + System.currentTimeMillis());
	tmp.mkdir();
	Runtime.getRuntime().addShutdownHook(new Thread() {
		
		@Override
		public void run() {

			try {
				FileUtils.deleteDirectory(tmp);
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	});
	return tmp;

}

This is preferred since apache commons the library that comes as closest to the asked "standard" and works with both JDK 7 and older versions. This also returns an "old" File instance (which is stream based) and not a "new" Path instance (which is buffer based and would be the result of JDK7's getTemporaryDirectory() method) -> Therefore it returns what most people need when they want to create a temporary directory.

Solution 15 - Java

Try this small example:

Code:

try {
    Path tmpDir = Files.createTempDirectory("tmpDir");
    System.out.println(tmpDir.toString());
    Files.delete(tmpDir);
} catch (IOException e) {
    e.printStackTrace();
}


Imports:
java.io.IOException
java.nio.file.Files
java.nio.file.Path

Console output on Windows machine:
C:\Users\userName\AppData\Local\Temp\tmpDir2908538301081367877

Comment:
Files.createTempDirectory generates unique ID atomatically - 2908538301081367877.

Note:
Read the following for deleting directories recursively:
https://stackoverflow.com/questions/779519/delete-directories-recursively-in-java

Solution 16 - Java

I like the multiple attempts at creating a unique name but even this solution does not rule out a race condition. Another process can slip in after the test for exists() and the if(newTempDir.mkdirs()) method invocation. I have no idea how to completely make this safe without resorting to native code, which I presume is what's buried inside File.createTempFile().

Solution 17 - Java

Before Java 7 you could also:

File folder = File.createTempFile("testFileUtils", ""); // no suffix
folder.delete();
folder.mkdirs();
folder.deleteOnExit();

Solution 18 - Java

Using File#createTempFile and delete to create a unique name for the directory seems ok. You should add a ShutdownHook to delete the directory (recursively) on JVM shutdown.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionPeter BeckerView Question on Stackoverflow
Solution 1 - JavaTofuBeerView Answer on Stackoverflow
Solution 2 - JavaSpinaView Answer on Stackoverflow
Solution 3 - JavamatsevView Answer on Stackoverflow
Solution 4 - JavaGreg PriceView Answer on Stackoverflow
Solution 5 - JavaAndres KievskyView Answer on Stackoverflow
Solution 6 - JavaDeveloper DudeView Answer on Stackoverflow
Solution 7 - JavaseekerView Answer on Stackoverflow
Solution 8 - JavaKeithView Answer on Stackoverflow
Solution 9 - JavaPaul TomblinView Answer on Stackoverflow
Solution 10 - JavaMichael MyersView Answer on Stackoverflow
Solution 11 - Javamatt bView Answer on Stackoverflow
Solution 12 - JavaArneView Answer on Stackoverflow
Solution 13 - JavaimmoteousView Answer on Stackoverflow
Solution 14 - JavaCarsten EngelkeView Answer on Stackoverflow
Solution 15 - JavaDigitShifterView Answer on Stackoverflow
Solution 16 - JavaChris LottView Answer on Stackoverflow
Solution 17 - JavageriView Answer on Stackoverflow
Solution 18 - JavaordnungswidrigView Answer on Stackoverflow