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


当前回答

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

其他回答

这是我决定为我自己的代码所做的:

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

正如您在其他答案中看到的,没有标准的方法出现。 因此你已经提到了Apache Commons,我建议使用Apache Commons IO中的FileUtils来实现以下方法:

/**
 * 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;

}

这是首选的,因为apache公共库是最接近所要求的“标准”的库,并且适用于JDK 7和旧版本。这也返回了一个“旧的”文件实例(基于流),而不是一个“新的”路径实例(基于缓冲区,将是JDK7的getTemporaryDirectory()方法的结果)->因此,当大多数人想要创建临时目录时,它返回了他们需要的东西。

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

这段代码应该可以很好地工作:

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

这是Guava库的Files.createTempDir()的源代码。它没有你想象的那么复杂:

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

默认情况下:

private static final int TEMP_DIR_ATTEMPTS = 10000;

在这里看到的