Java에서 임시 디렉토리/폴더를 만드는 방법?
Java 응용프로그램 내부에 임시 디렉토리를 만드는 표준적이고 신뢰할 수 있는 방법이 있는가?Java의 발행 데이터베이스에는 코드의 일부가 기재되어 있는 항목이 있지만, 일반적인 도서관 중 하나(APache Commons 등)에서 찾을 수 있는 표준 솔루션이 있는지 궁금하다.
JDK 7을 사용하는 경우 새 Files.create를 사용하십시오.임시 디렉터리를 만들 TempDirectory 클래스.
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)를 만들 수 있다.
구글 과바 도서관에는 많은 도움이 되는 유틸리티들이 있다.여기서 주목해야 할 것은 파일 클래스다.다음과 같은 여러 가지 유용한 방법이 있다.
File myTempDir = Files.createTempDir();
이것은 당신이 요구한 것을 정확히 한 줄로 한다.여기서 설명서를 읽으면 제안된 적응증의File.createTempFile("install", "dir")
일반적으로 보안 취약점을 도입한다.
만약 당신이 테스트를 위해 임시 디렉토리가 필요하고 당신이 jUnit을 사용하고 있다면,@Rule
TemporaryFolder
문제 해결:
@Rule
public TemporaryFolder folder = new TemporaryFolder();
설명서:
TemporaryFolder Rule은 테스트 메서드가 완료되었을 때 삭제될 수 있는 파일 및 폴더를 생성할 수 있도록 허용한다(통과 또는 실패 여부).
업데이트:
JUnit 목성(버전 5.1.1 이상)을 사용하는 경우 JUnit 5 Extension Pack인 JUnit Pional을 사용할 수 있는 옵션이 있다.
프로젝트 설명서에서 복사한 내용:
예를 들어, 다음의 테스트는 단일 테스트 방법에 대한 확장자를 등록하고, 임시 디렉터리에 파일을 만들어 쓰고, 그 내용을 확인한다.
@Test
@ExtendWith(TempDirectory.class)
void test(@TempDir Path tempDir) {
Path file = tempDir.resolve("test.txt");
writeFile(file);
assertExpectedFileContent(file);
}
TempDirectory의 JavaDoc 및 JavaDoc에 대한 추가 정보
그라들:
dependencies {
testImplementation 'org.junit-pioneer:junit-pioneer:0.1.2'
}
메이븐:
<dependency>
<groupId>org.junit-pioneer</groupId>
<artifactId>junit-pioneer</artifactId>
<version>0.1.2</version>
<scope>test</scope>
</dependency>
업데이트 2:
@TempDir 주석은 실험적인 특징으로 JUnit Jurist 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));
}
이 문제를 해결하기 위해 순진하게 작성된 코드는 여기에 있는 몇 가지 해답을 포함한 인종적 조건에 시달리고 있다.역사적으로 당신은 인종 조건에 대해 신중히 생각하고 그것을 직접 쓸 수도 있고, 구글의 구아바와 같은 제3자 도서관을 이용할 수도 있다(스피나의 대답대로).아니면 버기 코드를 쓸 수도 있다.
하지만 JDK 7은 좋은 소식이 있어!자바 표준 라이브러리 자체는 이제 이 문제에 대한 적절한 (비-레이시) 해결책을 제공한다.java.nio.file을 원하는 경우.파일#생성TempDirectory()설명서:
public static Path createTempDirectory(Path dir,
String prefix,
FileAttribute<?>... attrs)
throws IOException
지정된 접두사를 사용하여 지정된 디렉터리에 새 디렉터리를 생성하십시오.결과 Path는 지정된 디렉토리와 동일한 FileSystem과 연결된다.
디렉터리 이름이 생성되는 방법에 대한 상세 내역은 구현에 따라 달라지므로 지정되지 않는다.가능한 경우 접두사는 후보 이름을 구성하는 데 사용된다.
이것은 단지 그러한 기능을 요구하는 태양 벌레 추적기의 당혹스러울 정도로 오래된 벌레 보고서를 효과적으로 해결한다.
이것은 Guava 라이브러리의 Files.create에 대한 소스 코드 입니다.TempDir()당신이 생각하는 것만큼 복잡한 곳은 없다.
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;
사용 안 함deleteOnExit()
나중에 명시적으로 삭제하더라도.
구글 'deleteonexit is devil'은 더 많은 정보를 얻으려고 하지만, 문제의 요지는 다음과 같다.
deleteOnExit()
정상적인 JVM 종료에 대해서만 삭제하며, JVM 프로세스를 중단하거나 종료하지 않는다.deleteOnExit()
JVM 종료 시에만 삭제 - 다음과 같은 이유로 오랫동안 실행 중인 서버 프로세스에는 적합하지 않다.그 중에서도 가장 악한 것은-
deleteOnExit()
각 임시 파일 입력에 대해 메모리를 소모한다.프로세스가 몇 개월 동안 실행 중이거나 짧은 시간에 많은 임시 파일을 생성하는 경우, 메모리를 소모하고 JVM이 종료될 때까지 절대 해제하지 마십시오.
자바 1.7 기준createTempDirectory(prefix, attrs)
그리고createTempDirectory(dir, prefix, attrs)
에 포함되다java.nio.file.Files
예:File tempDir = Files.createTempDirectory("foobar").toFile();
이것이 내가 내 코드로 하기로 결정한 것이다.
/**
* 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();
}
음, "만들기"TempFile"은 실제로 파일을 만든다.그러니 그냥 먼저 지우고, 그 위에 mkdir를 하는 게 어때?
이 코드는 합리적으로 잘 작동해야 한다.
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;
}
본 RFE와 그 논평에서 논의된 바와 같이, 당신은 전화할 수 있다.tempDir.delete()
ㅁㅁ. ㅁ. ㅁ. ㅁ.System.getProperty("java.io.tmpdir")
거기에 디렉토리를 만드세요.어느 쪽이든, 당신은 잊지 말고 전화해야 한다.tempDir.deleteOnExit()
또는 작업을 마친 후 파일이 삭제되지 않을 경우.
단지 완성을 위해, 이것은 구글 구아바 도서관에서 나온 코드다.내 코드는 아니지만, 이 실에 여기에 보여주는 것은 가치가 있다고 생각한다.
/** 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)
+ ')');
}
나도 같은 문제를 맞았으니 이것은 관심 있는 사람들을 위한 또 다른 대답일 뿐이며, 이는 위의 대답 중 하나와 유사하다.
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());
}
}
}
}
});
콜스택(완전히 선택 사항이며 현 시점에서 재귀로 할 수 있다)을 사용하지 않고, 임시 삭제 전에 모든 하위 업무와 파일을 삭제하는 방법이지만, 나는 안전한 편에 서고 싶다.
다른 답변에서도 알 수 있듯이, 표준적인 접근은 일어나지 않았다.따라서 이미 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 버전과 이전 버전 모두에서 작동하는 라이브러리를 공유하기 때문에 선호된다.이것은 또한 "새로운" 경로 인스턴스(buffer 기반이며 JDK7의 getTemporaryDirectory() 방법의 결과물이 될 수 있음)가 아닌 "구" 파일 인스턴스(스트림 기반)를 반환하므로 대부분의 사용자가 임시 디렉토리를 만들고 싶을 때 필요한 것을 반환한다.
다음과 같은 작은 예를 들어 보십시오.
코드:
try {
Path tmpDir = Files.createTempDirectory("tmpDir");
System.out.println(tmpDir.toString());
Files.delete(tmpDir);
} catch (IOException e) {
e.printStackTrace();
}
가져오기:
java.io.IOException
java.nio.file.파일
java.nio.file.경로
윈도우즈 시스템의 콘솔 출력:
C:\Users\userName\AppData\Local\온도\tmpDir2908538301081367877
설명:
파일.생성TempDirectory는 2908538301081367877의 고유한 ID를 생성한다.
참고:
디렉터리를 반복적으로 삭제하려면 다음을 읽으십시오.
Java에서 반복적으로 디렉토리 삭제
나는 독특한 이름을 만들려는 여러 시도를 좋아하지만 이 해결책조차도 인종 조건을 배제하지 않는다.다음에 대한 테스트 후 다른 프로세스가 미끄러져 들어올 수 있음exists()
그리고if(newTempDir.mkdirs())
방법 호출나는 이것을 어떻게 완전히 안전하게 만들 수 있을지는 전혀 알지 못하는데, 나는 그것이 안에 묻혀 있는 것이라고 추측한다.File.createTempFile()
.
Java 7 이전에 다음 작업을 수행할 수도 있다.
File folder = File.createTempFile("testFileUtils", ""); // no suffix
folder.delete();
folder.mkdirs();
folder.deleteOnExit();
사용.File#createTempFile
, 그리고delete
디렉토리의 고유한 이름을 만드는 것은 괜찮아 보인다.A를 추가하십시오.ShutdownHook
JVM 종료 시 디렉터리(재발적으로)를 삭제하십시오.
참조URL: https://stackoverflow.com/questions/617414/how-to-create-a-temporary-directory-folder-in-java
'IT이야기' 카테고리의 다른 글
Vue JS에서 v-for를 사용하여 구성 요소에 대한 소품 설정 (0) | 2022.04.25 |
---|---|
Ubuntu 아래에 JDK 11을 설치하는 방법? (0) | 2022.04.25 |
복합 C 선언 (0) | 2022.04.25 |
다른 엔드 Vue, JS인 경우 실행 기능 (0) | 2022.04.25 |
확인란 및 드래그 드롭이 있는 트리 구현 (0) | 2022.04.25 |