如何在 Java 中创建临时目录/文件夹?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/617414/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to create a temporary directory/folder in Java?
提问by Peter Becker
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 应用程序中创建临时目录的标准且可靠的方法?Java 的问题数据库中有一个条目,注释中有一些代码,但我想知道在常用库之一(Apache Commons 等)中是否可以找到标准解决方案?
采纳答案by TofuBeer
If you are using JDK 7 use the new Files.createTempDirectoryclass to create the temporary directory.
如果您使用的是 JDK 7,请使用新的Files.createTempDirectory类来创建临时目录。
Path tempDirWithPrefix = Files.createTempDirectory(prefix);
Before JDK 7 this should do it:
在 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);
}
You could make better exceptions (subclass IOException) if you want.
如果需要,您可以创建更好的异常(子类 IOException)。
回答by Paul Tomblin
Well, "createTempFile" actually creates the file. So why not just delete it first, and then do the mkdir on it?
好吧,“createTempFile”实际上创建了文件。那么为什么不先删除它,然后在上面做 mkdir 呢?
回答by Michael Myers
As discussed in this RFEand 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.
如本 RFE及其评论中所述,您可以tempDir.delete()
先致电。或者您可以System.getProperty("java.io.tmpdir")
在那里使用并创建一个目录。无论哪种方式,您都应该记住调用tempDir.deleteOnExit()
,否则完成后文件不会被删除。
回答by matt b
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;
}
回答by ordnungswidrig
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.
使用File#createTempFile
和delete
为目录创建唯一名称似乎没问题。您应该添加 aShutdownHook
以在 JVM 关闭时删除目录(递归)。
回答by Keith
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();
}
回答by Developer Dude
Do not use deleteOnExit()
even if you explicitly delete it later.
deleteOnExit()
即使您稍后明确删除它,也不要使用。
Google 'deleteonexit is evil'for more info, but the gist of the problem is:
谷歌“deleteonexit is evil”了解更多信息,但问题的要点是:
deleteOnExit()
only deletes for normal JVM shutdowns, not crashes or killing the JVM process.deleteOnExit()
only deletes on JVM shutdown - not good for long running server processes because: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.
deleteOnExit()
仅在正常 JVM 关闭时删除,不会崩溃或终止 JVM 进程。deleteOnExit()
仅在 JVM 关闭时删除 - 不适用于长时间运行的服务器进程,因为:最邪恶的 -
deleteOnExit()
每个临时文件条目消耗内存。如果您的进程运行了数月,或者在短时间内创建了大量临时文件,您将消耗内存并且永远不会释放它,直到 JVM 关闭。
回答by Chris Lott
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()
.
我喜欢创建唯一名称的多次尝试,但即使此解决方案也不排除竞争条件。另一个进程可以在测试exists()
和if(newTempDir.mkdirs())
方法调用之后插入。我不知道如何在不求助于本机代码的情况下完全使其安全,我认为这是隐藏在File.createTempFile()
.
回答by matsev
If you need a temporary directory for testing and you are using jUnit, @Rule
together with TemporaryFolder
solves your problem:
如果您需要一个用于测试的临时目录并且您正在使用 jUnit,那么@Rule
连同TemporaryFolder
解决您的问题:
@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)
TemporaryFolder Rule 允许创建文件和文件夹,这些文件和文件夹保证在测试方法完成时(无论通过还是失败)被删除
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.
如果您使用的是 JUnit Jupiter(版本 5.1.1 或更高版本),您可以选择使用 JUnit Pioneer,它是 JUnit 5 扩展包。
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 JavaDocand the JavaDoc of TempDirectory
JavaDoc和TempDirectory的JavaDoc 中的更多信息
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:
更新 2:
The @TempDirannotation was added to the JUnit Jupiter 5.4.0 release as an experimental feature. Example copied from the JUnit 5 User Guide:
该@TempDir注释添加到JUnit的木星5.4.0版本作为实验性的功能。从JUnit 5 用户指南复制的示例:
@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));
}
回答by Spina
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:
Google Guava 库有大量有用的实用程序。这里的一个注意事项是Files 类。它有很多有用的方法,包括:
File myTempDir = Files.createTempDir();
This does exactly what you asked for in one line. If you read the documentation hereyou'll see that the proposed adaptation of File.createTempFile("install", "dir")
typically introduces security vulnerabilities.
这正是您在一行中要求的。如果您阅读此处的文档,您会发现建议的改编File.createTempFile("install", "dir")
通常会引入安全漏洞。