有没有在Java应用程序内部创建临时目录的标准可靠方法? Java的问题数据库中有一个条目,注释中包含一些代码,但是我想知道在一个常用的库(Apache Commons等)中是否找到标准解决方案?


#1楼

这是我决定为自己的代码执行的操作:

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

#2楼

我遇到了同样的问题,所以这只是对那些有兴趣的人的另一个答案,它与上述之一相似:

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

对于我的应用程序,我决定添加一个选项来清除退出时的温度 ,因此我添加了一个关闭挂钩:

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

该方法在删除temp之前先删除所有子目录和文件,而不使用调用栈(这是完全可选的,此时您可以使用递归进行此操作),但是我想保持安全。


#3楼

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

谷歌“ deleteonexit”以获得更多信息,但是问题的要点是:

  1. deleteOnExit()仅在正常JVM关闭时删除,而不会崩溃或杀死JVM进程。
  2. deleteOnExit()仅在JVM关闭时删除-对于长时间运行的服务器进程来说不好,因为:
  3. deleteOnExit()消耗每个临时文件条目的内存。 如果您的进程运行了几个月,或者在很短的时间内创建了许多临时文件,则您将消耗内存,并且在JVM关闭之前永远不要释放内存。

#4楼

正如您在其他答案中看到的那样,没有标准的方法出现。 因此,您已经提到了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 commons是最接近要求的“标准”的库,并且可与JDK 7和更早版本一起使用。 这还会返回一个“旧” File实例(基于流),而不是一个“ new” Path实例(基于缓冲区,这是JDK7的getTemporaryDirectory()方法的结果)->因此,它返回大多数人在需要时他们想创建一个临时目录。