411 votes

Comment créer un répertoire/dossier temporaire en Java ?

Existe-t-il un moyen standard et fiable de créer un répertoire temporaire dans une application Java ? Il y a une entrée dans la base de données des problèmes de Java Je me demande s'il n'y a pas une solution standard à trouver dans l'une des bibliothèques habituelles (Apache Commons, etc.) ?

435voto

TofuBeer Points 32441

Si vous utilisez le JDK 7, utilisez le nouveau fichier Fichiers.createTempDirectory pour créer le répertoire temporaire.

Path tempDirWithPrefix = Files.createTempDirectory(prefix);

Avant le JDK 7, cela devrait suffire :

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

Vous pourriez créer de meilleures exceptions (sous-classe IOException) si vous le souhaitez.

0 votes

C'est une bonne idée de réutiliser le nom temporaire garanti.

12 votes

C'est dangereux. Java est connu pour ne pas supprimer les fichiers immédiatement, donc mkdir peut parfois échouer.

5 votes

@Demiurg Le seul cas où un fichier n'est pas supprimé immédiatement est sous Windows lorsque le fichier est déjà ouvert (il peut être ouvert par un antivirus par exemple). Avez-vous d'autres documents pour démontrer le contraire (je suis curieux de ce genre de choses :-) ? Si cela se produit régulièrement, alors le code ci-dessus ne fonctionnera pas, si c'est rare, le fait de supprimer l'appel au code ci-dessus jusqu'à ce que la suppression se produise (ou qu'un nombre maximum d'essais soit atteint) fonctionnerait.

184voto

Spina Points 2769

La bibliothèque Guava de Google contient une tonne d'utilitaires utiles. L'un d'entre eux est le Classe de dossiers . Il dispose d'un grand nombre de méthodes utiles, notamment :

File myTempDir = Files.createTempDir();

Cela fait exactement ce que vous avez demandé en une ligne. Si vous lisez la documentation [ici](http://google.github.io/guava/releases/19.0/api/docs/com/google/common/io/Files.html#createTempDir()) vous verrez que l'adaptation proposée de File.createTempFile("install", "dir") introduit généralement des failles de sécurité.

0 votes

Je me demande à quelle vulnérabilité vous faites référence. Cette approche ne semble pas créer de situation de course car File.mkdir() est censé échouer si un tel répertoire existe déjà (créé par un attaquant). Je ne pense pas non plus que cet appel suivra un lien symbolique malveillant. Pourriez-vous préciser ce que vous avez voulu dire ?

3 votes

@abb : Je ne connais pas les détails de la condition de course qui est mentionnée dans la documentation de Guava. Je soupçonne que la documentation est correcte étant donné qu'elle signale spécifiquement le problème.

1 votes

@abb Vous avez raison. Tant que le retour de mkdir() est vérifié, ce serait sécurisé. Le code vers lequel Spina pointe utilise cette méthode mkdir(). grepcode.com/file/repo1.maven.org/maven2/com.google.guava/guava/ . Ce n'est qu'un problème potentiel sur les systèmes Unix lors de l'utilisation du répertoire /tmp car le sticky bit y est activé.

179voto

matsev Points 6761

Si vous avez besoin d'un répertoire temporaire pour les tests et que vous utilisez jUnit, @Rule en même temps que TemporaryFolder résout votre problème :

@Rule
public TemporaryFolder folder = new TemporaryFolder();

De la documentation :

La règle TemporaryFolder permet de créer des fichiers et des dossiers dont la suppression est garantie à la fin de la méthode de test (qu'elle réussisse ou échoue).


Mise à jour :

Si vous utilisez JUnit Jupiter (version 5.1.1 ou supérieure), vous avez la possibilité d'utiliser JUnit Pioneer qui est le JUnit 5 Extension Pack.

Copié de la la documentation du projet :

Par exemple, le test suivant enregistre l'extension pour une seule méthode de test, crée et écrit un fichier dans le répertoire temporaire et vérifie son contenu.

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

Plus d'informations dans le JavaDoc et le JavaDoc de 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>

Mise à jour 2 :

Le site @TempDir a été ajoutée à la version 5.4.0 de JUnit Jupiter en tant que fonctionnalité expérimentale. Exemple copié de la Guide de l'utilisateur de 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));
}

0 votes

Ne fonctionne pas dans JUnit 4.8.2 sur Windows 7 ! (problème de permissions)

2 votes

@CraigRinger : Pourquoi est-il imprudent de se fier à cela ?

2 votes

@AdamParkin Honnêtement, je ne me souviens plus. Echec de l'explication !

43voto

Greg Price Points 1901

Le code écrit naïvement pour résoudre ce problème souffre de conditions de course, y compris plusieurs des réponses ici. Historiquement, vous pouviez réfléchir soigneusement aux conditions de course et l'écrire vous-même, ou vous pouviez utiliser une bibliothèque tierce comme Guava de Google (comme le suggère la réponse de Spina).

Mais à partir du JDK 7, il y a de bonnes nouvelles ! La bibliothèque standard Java elle-même fournit désormais une solution (non racoleuse) à ce problème. Vous voulez java.nio.file.Files#createTempDirectory() . De la documentation :

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

Crée un nouveau répertoire dans le répertoire spécifié, en utilisant le préfixe donné pour générer son nom. Le chemin résultant est associé au même système de fichiers que le répertoire donné.

Les détails sur la façon dont le nom du répertoire est construit dépendent de l'implémentation et ne sont donc pas spécifiés. Dans la mesure du possible, le préfixe est utilisé pour construire les noms des candidats.

Cela résout efficacement le problème de rapport de bug ancien et embarrassant dans le bug tracker de Sun qui demandait justement une telle fonction.

38voto

ank Points 1909

Voici le code source de la fonction Files.createTempDir() de la bibliothèque Guava. Ce n'est pas aussi complexe que vous pourriez le penser :

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) + ')');
}

Par défaut :

private static final int TEMP_DIR_ATTEMPTS = 10000;

Voir ici

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X