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 , qui contient un peu de code dans les commentaires, mais je me demande s'il existe une solution standard dans l'une des bibliothèques habituelles (Apache Commons, etc.)?
365
temp.delete(); temp = new File(temp.getPath + ".d"); temp.mkdir(); ..., temp.delete();
.delete()
etmkdir()
: Un processus malveillant pourrait créer le répertoire cible dans l'intervalle (en prenant le nom du fichier récemment créé). VoirFiles.createTempDir()
pour une alternative.La bibliothèque Google Guava possède une tonne d'utilitaires utiles. L'une des notes ici est la classe Files . Il a un tas de méthodes utiles, notamment:
Cela fait exactement ce que vous avez demandé en une seule ligne. Si vous lisez la documentation ici, vous verrez que l'adaptation proposée de
File.createTempFile("install", "dir")
introduit généralement des vulnérabilités de sécurité.la source
Si vous avez besoin d' un répertoire temporaire pour les tests et que vous utilisez JUnit,
@Rule
ainsiTemporaryFolder
résout votre problème:De la documentation :
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 pack d'extension JUnit 5.
Copié de la documentation du projet :
Plus d'informations dans le JavaDoc et le JavaDoc de TempDirectory
Gradle:
Maven:
Mise à jour 2:
L' annotation @TempDir a été ajoutée à la version JUnit Jupiter 5.4.0 en tant que fonctionnalité expérimentale. Exemple copié à partir du Guide de l'utilisateur de JUnit 5 :
la source
Un code naïvement écrit pour résoudre ce problème souffre de conditions de concurrence, y compris plusieurs des réponses ici. Historiquement, vous pouvez bien réfléchir aux conditions de concurrence et l'écrire vous-même, ou vous pouvez utiliser une bibliothèque tierce comme Google's Guava (comme le suggère la réponse de Spina). Ou vous pouvez écrire du code buggy.
Mais depuis JDK 7, il y a de bonnes nouvelles! La bibliothèque standard Java elle-même fournit désormais une solution (non racée) fonctionnant correctement à ce problème. Vous voulez java.nio.file.Files # createTempDirectory () . De la documentation :
Cela résout efficacement l' ancien rapport de bogue embarrassant dans le traqueur de bogues Sun qui demandait juste une telle fonction.
la source
Il s'agit du code source de Files.createTempDir () de la bibliothèque Guava. Ce n'est nulle part aussi complexe que vous pourriez le penser:
Par défaut:
Vois ici
la source
Ne l'utilisez pas
deleteOnExit()
même si vous le supprimez explicitement ultérieurement.Google 'deleteonexit is evil' pour plus d'informations, mais l'essentiel du problème est:
deleteOnExit()
supprime uniquement pour les arrêts JVM normaux, pas de plantages ou de tuer le processus JVM.deleteOnExit()
supprime uniquement lors de l'arrêt de la machine virtuelle Java - n'est pas bon pour les processus serveur de longue durée car:Le plus mauvais de tous -
deleteOnExit()
consomme de la mémoire pour chaque entrée de fichier temporaire. Si votre processus s'exécute pendant des mois ou crée de nombreux fichiers temporaires en peu de temps, vous consommez de la mémoire et ne la libérez jamais tant que la JVM ne s'est pas arrêtée.la source
Depuis Java 1.7
createTempDirectory(prefix, attrs)
etcreateTempDirectory(dir, prefix, attrs)
sont inclus dansjava.nio.file.Files
Exemple:
File tempDir = Files.createTempDirectory("foobar").toFile();
la source
C'est ce que j'ai décidé de faire pour mon propre code:
la source
Eh bien, "createTempFile" crée réellement le fichier. Alors pourquoi ne pas simplement le supprimer d'abord, puis faire le mkdir dessus?
la source
Ce code devrait fonctionner raisonnablement bien:
la source
Comme discuté dans cette RFE et ses commentaires, vous pouvez appeler en
tempDir.delete()
premier. Ou vous pouvez utiliserSystem.getProperty("java.io.tmpdir")
et créer un répertoire là-bas. Dans tous les cas, n'oubliez pas d'appelertempDir.deleteOnExit()
, sinon le fichier ne sera pas supprimé une fois que vous aurez terminé.la source
Juste pour l'achèvement, c'est le code de la bibliothèque google guava. Ce n'est pas mon code, mais je pense qu'il est utile de le montrer ici dans ce fil.
la source
J'ai le même problème donc c'est juste une autre réponse pour ceux qui sont intéressés, et c'est similaire à l'une des réponses ci-dessus:
Et pour mon application, j'ai décidé d'ajouter une option pour effacer la température à la sortie, j'ai donc ajouté un crochet d'arrêt:
La méthode supprime tous les sous-répertoires et fichiers avant de supprimer le temp , sans utiliser la pile d'appels (qui est totalement facultative et vous pouvez le faire avec la récursivité à ce stade), mais je veux être du bon côté.
la source
Comme vous pouvez le voir dans les autres réponses, aucune approche standard n'est apparue. Par conséquent, vous avez déjà mentionné Apache Commons, je propose l'approche suivante en utilisant FileUtils d' Apache Commons IO :
Ceci est préférable car apache met en commun la bibliothèque qui se rapproche le plus de la "norme" demandée et fonctionne avec JDK 7 et les versions plus anciennes. Cela renvoie également une "ancienne" instance de fichier (qui est basée sur un flux) et non une "nouvelle" instance de chemin (qui est basée sur un tampon et qui serait le résultat de la méthode getTemporaryDirectory () de JDK7) -> Par conséquent, elle renvoie ce dont la plupart des gens ont besoin lorsque ils veulent créer un répertoire temporaire.
la source
J'aime les multiples tentatives de création d'un nom unique, mais même cette solution n'exclut pas une condition de concurrence. Un autre processus peut se glisser après le test
exists()
et l'if(newTempDir.mkdirs())
invocation de la méthode. Je n'ai aucune idée de comment sécuriser complètement cela sans recourir au code natif, qui, je suppose, est ce qui est enterré à l'intérieurFile.createTempFile()
.la source
Avant Java 7, vous pouviez également:
la source
Essayez ce petit exemple:
Code:
Importations:
java.io.IOException
java.nio.file.Files
java.nio.file.Path
Sortie de la console sur la machine Windows:
C: \ Users \ userName \ AppData \ Local \ Temp \ tmpDir2908538301081367877
Commentaire:
Files.createTempDirectory génère automatiquement un ID unique - 2908538301081367877.
Remarque:
lisez ce qui suit pour supprimer les répertoires récursivement:
Supprimer les répertoires récursivement en Java
la source
Utiliser
File#createTempFile
etdelete
pour créer un nom unique pour le répertoire semble correct. Vous devez ajouter unShutdownHook
pour supprimer le répertoire (récursivement) lors de l'arrêt de la JVM.la source