是否有一种在Java应用程序中创建临时目录的标准而可靠的方法?在Java的问题数据库中有一个条目,在评论中有一些代码,但我想知道在一个常用的库(Apache Commons等)中是否有一个标准的解决方案?


当前回答

如果您使用的是JDK 7,请使用新的Files。类创建临时目录。

Path tempDirWithPrefix = Files.createTempDirectory(prefix);

在JDK 7之前,应该这样做:

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);
}

如果你愿意,你可以创建更好的异常(子类IOException)。

其他回答

只是为了完成,这是谷歌番石榴库的代码。这不是我的代码,但我认为在这个线程中展示它是有价值的。

  /** 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)
            + ')');
  }

使用file# createTempFile和delete为目录创建一个唯一的名称似乎是可以的。您应该添加一个ShutdownHook,以便在JVM关闭时(递归地)删除目录。

如果您使用的是JDK 7,请使用新的Files。类创建临时目录。

Path tempDirWithPrefix = Files.createTempDirectory(prefix);

在JDK 7之前,应该这样做:

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);
}

如果你愿意,你可以创建更好的异常(子类IOException)。

我喜欢创建唯一名称的多次尝试,但即使是这种解决方案也不排除竞争条件。另一个进程可以在exists()和if(newTempDir.mkdirs())方法调用测试之后插入。我不知道如何在不求助于本机代码的情况下完全使其安全,我认为这是隐藏在File.createTempFile()中的内容。

即使稍后显式删除它,也不要使用deleteOnExit()。

谷歌'deleteonexit is evil'获取更多信息,但问题的要点是:

deleteOnExit()只删除正常的JVM关闭,不删除崩溃或杀死JVM进程。 deleteOnExit()只在JVM关闭时删除-不适合长时间运行的服务器进程,因为: 最糟糕的是deleteOnExit()为每个临时文件条目消耗内存。如果您的进程运行了几个月,或者在短时间内创建了大量临时文件,那么您将消耗内存,直到JVM关闭才释放内存。