Как создать временный каталог / папку в Java? - PullRequest
324 голосов
/ 06 марта 2009

Существует ли стандартный и надежный способ создания временного каталога в приложении Java? В базе данных проблем Java есть запись , в которой есть небольшой код в комментариях, но мне интересно, есть ли стандартное решение, которое можно найти в одной из обычных библиотек (Apache Commons и т. Д.)?

Ответы [ 17 ]

347 голосов
/ 06 марта 2009

Если вы используете JDK 7, используйте новый класс Files.createTempDirectory для создания временного каталога.

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), если хотите.

178 голосов
/ 19 июня 2011

В библиотеке Google Guava есть множество полезных утилит. Здесь следует отметить класс Files . Он имеет множество полезных методов, в том числе:

File myTempDir = Files.createTempDir();

Это делает именно то, что вы просили в одной строке. Если вы прочитаете документацию здесь , то увидите, что предлагаемая адаптация File.createTempFile("install", "dir") обычно представляет уязвимости безопасности.

153 голосов
/ 31 мая 2011

Если вам нужен временный каталог для тестирования и вы используете jUnit, @Rule вместе с TemporaryFolder решит вашу проблему:

@Rule
public TemporaryFolder folder = new TemporaryFolder();

Из документации :

Правило TemporaryFolder позволяет создавать файлы и папки, которые гарантированно удаляются после завершения метода тестирования (независимо от того, пройден он или нет)


Обновление:

Если вы используете JUnit Jupiter (версия 5.1.1 или выше), у вас есть возможность использовать JUnit Pioneer, который является пакетом расширения JUnit 5.

Скопировано из проектной документации :

Например, следующий тест регистрирует расширение для одного метода теста, создает и записывает файл во временный каталог и проверяет его содержимое.

@Test
@ExtendWith(TempDirectory.class)
void test(@TempDir Path tempDir) {
    Path file = tempDir.resolve("test.txt");
    writeFile(file);
    assertExpectedFileContent(file);
}

Дополнительная информация в JavaDoc и JavaDoc TempDirectory

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>

Обновление 2:

Аннотация @ TempDir была добавлена ​​в выпуск JUnit Jupiter 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));
}
39 голосов
/ 18 октября 2011

Наивно написанный код для решения этой проблемы страдает от условий гонки, в том числе несколько ответов здесь. Исторически сложилось так, что вы могли тщательно обдумать условия гонки и написать ее самостоятельно, или вы могли бы использовать стороннюю библиотеку, такую ​​как Google Guava (как подсказал ответ Спины). Или вы могли бы написать глючный код.

Но с JDK 7 есть хорошие новости! Сама стандартная библиотека Java теперь предоставляет правильно работающее (нерасовое) решение этой проблемы. Вы хотите java.nio.file.Files # createTempDirectory () . Из документации :

public static Path createTempDirectory(Path dir,
                       String prefix,
                       FileAttribute<?>... attrs)
                                throws IOException

Создает новый каталог в указанном каталоге, используя данный префикс для генерации его имени. Результирующий путь связан с той же файловой системой, что и данный каталог.

Сведения о том, как создается имя каталога, зависят от реализации и поэтому не указаны. Там, где это возможно, префикс используется для создания имен кандидатов.

Это эффективно разрешает смущающее древнее сообщение об ошибке в системе отслеживания ошибок Sun, которая запрашивала именно такую ​​функцию.

34 голосов
/ 25 января 2012

Это исходный код для Files.createTempDir () библиотеки Guava. Это нигде не так сложно, как вы думаете:

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;

Смотрите здесь

25 голосов
/ 02 октября 2009

Не используйте deleteOnExit(), даже если вы явно удалите его позже.

Google 'deleteonexit is evil' для получения дополнительной информации, но суть проблемы:

  1. deleteOnExit() удаляет только для обычных остановок JVM, а не для сбоев и не прерывает процесс JVM.

  2. deleteOnExit() удаляет только при завершении работы JVM - не подходит для длительных процессов сервера, потому что:

  3. Самое злое из всех - deleteOnExit() потребляет память для каждой записи временного файла. Если ваш процесс выполняется в течение нескольких месяцев или в течение короткого времени создает много временных файлов, вы расходуете память и никогда не освобождаете ее, пока JVM не отключится.

20 голосов
/ 10 января 2012

Начиная с Java 1,7 createTempDirectory(prefix, attrs) и createTempDirectory(dir, prefix, attrs) включены в java.nio.file.Files

Пример: File tempDir = Files.createTempDirectory("foobar").toFile();

14 голосов
/ 20 августа 2009

Это то, что я решил сделать для своего собственного кода:

/**
 * 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();
}
5 голосов
/ 17 декабря 2008

Хорошо, "createTempFile" фактически создает файл. Так почему бы просто не удалить его сначала, а затем выполнить на нем mkdir?

3 голосов
/ 17 декабря 2008

Этот код должен работать достаточно хорошо:

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;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...