Pet*_*ker 338 java directory file-io file temporary-directory
是否有一种在Java应用程序中创建临时目录的标准且可靠的方法?Java的问题数据库中有一个条目,在评论中有一些代码,但我想知道是否有一个标准的解决方案可以在其中一个常见的库(Apache Commons等)中找到?
Tof*_*eer 363
如果您使用的是JDK 7,请使用新的Files.createTempDirectory类来创建临时目录.
Path tempDirWithPrefix = Files.createTempDirectory(prefix);
Run Code Online (Sandbox Code Playgroud)
在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);
}
Run Code Online (Sandbox Code Playgroud)
如果需要,可以创建更好的异常(子类IOException).
Spi*_*ina 181
Google Guava库有很多实用工具.其中一个值得注意的是Files类.它有许多有用的方法,包括:
File myTempDir = Files.createTempDir();
Run Code Online (Sandbox Code Playgroud)
这完全符合您在一行中提出的要求.如果你阅读这里的文档,你会发现建议的改编File.createTempFile("install", "dir")
通常会引入安全漏洞.
mat*_*sev 160
如果您需要进行测试的临时目录,并且您使用JUnit,@Rule
一起TemporaryFolder
解决您的问题:
@Rule
public TemporaryFolder folder = new TemporaryFolder();
Run Code Online (Sandbox Code Playgroud)
从文档:
TemporaryFolder规则允许创建在测试方法完成时保证删除的文件和文件夹(无论是通过还是失败)
更新:
如果您使用的是JUnit Jupiter(版本5.1.1或更高版本),则可以选择使用JUnit Pioneer,它是JUnit 5 Extension Pack.
从项目文档中复制:
例如,以下测试为单个测试方法注册扩展,创建文件并将其写入临时目录并检查其内容.
@Test
@ExtendWith(TempDirectory.class)
void test(@TempDir Path tempDir) {
Path file = tempDir.resolve("test.txt");
writeFile(file);
assertExpectedFileContent(file);
}
Run Code Online (Sandbox Code Playgroud)
JavaDoc和TempDirectory的JavaDoc中的更多信息
摇篮:
dependencies {
testImplementation 'org.junit-pioneer:junit-pioneer:0.1.2'
}
Run Code Online (Sandbox Code Playgroud)
Maven的:
<dependency>
<groupId>org.junit-pioneer</groupId>
<artifactId>junit-pioneer</artifactId>
<version>0.1.2</version>
<scope>test</scope>
</dependency>
Run Code Online (Sandbox Code Playgroud)
更新2:
该@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));
}
Run Code Online (Sandbox Code Playgroud)
Gre*_*ice 41
用于解决此问题的天真编写的代码会受到竞争条件的影响,包括此处的几个答案.从历史上看,您可以仔细考虑竞争条件并自行编写,或者您可以使用像Google的Guava这样的第三方库(如Spina的回答所示.)或者您可以编写有缺陷的代码.
但是从JDK 7开始,有好消息!Java标准库本身现在为这个问题提供了一个正常工作(非生动)的解决方案.你想要java.nio.file.Files #createTempDirectory().从文档:
public static Path createTempDirectory(Path dir,
String prefix,
FileAttribute<?>... attrs)
throws IOException
Run Code Online (Sandbox Code Playgroud)
在指定目录中创建一个新目录,使用给定的前缀生成其名称.生成的Path与给定目录的文件系统相关联.
有关如何构造目录名称的详细信息取决于实现,因此未指定.在可能的情况下,前缀用于构造候选名称.
这有效地解决了Sun bug追踪器中令人尴尬的古老bug报告,该报告要求提供这样的功能.
And*_*sky 34
这是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) + ')');
}
Run Code Online (Sandbox Code Playgroud)
默认情况下:
private static final int TEMP_DIR_ATTEMPTS = 10000;
Run Code Online (Sandbox Code Playgroud)
小智 26
deleteOnExit()
即使您稍后明确删除它也不要使用.
谷歌'deleteonexit是邪恶'获取更多信息,但问题的要点是:
deleteOnExit()
仅删除正常JVM关闭,而不是崩溃或终止JVM进程.
deleteOnExit()
仅在JVM关闭时删除 - 不适合长时间运行的服务器进程,因为:
最邪恶的 - deleteOnExit()
消耗每个临时文件条目的内存.如果您的进程运行了几个月,或者在短时间内创建了大量临时文件,那么您将消耗内存,并且在JVM关闭之前永远不会释放它.
see*_*ker 20
从Java 1.7开始createTempDirectory(prefix, attrs)
,createTempDirectory(dir, prefix, attrs)
包括在内java.nio.file.Files
例:
File tempDir = Files.createTempDirectory("foobar").toFile();
Kei*_*ith 14
这就是我决定为自己的代码做的事情:
/**
* 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();
}
Run Code Online (Sandbox Code Playgroud)