Gibt es eine standardmäßige und zuverlässige Methode zum Erstellen eines temporären Verzeichnisses in einer Java-Anwendung? Es gibt einen Eintrag in Javas Problemdatenbank , der ein wenig Code in den Kommentaren enthält, aber ich frage mich, ob es eine Standardlösung in einer der üblichen Bibliotheken (Apache Commons usw.) gibt.
364
temp.delete(); temp = new File(temp.getPath + ".d"); temp.mkdir(); ..., temp.delete();
.delete()
undmkdir()
: Ein böswilliger Prozess könnte in der Zwischenzeit das Zielverzeichnis erstellen (unter Verwendung des Namens der kürzlich erstellten Datei). SieheFiles.createTempDir()
für eine Alternative.Die Google Guava-Bibliothek enthält eine Menge hilfreicher Dienstprogramme. Bemerkenswert ist hier die Files-Klasse . Es gibt eine Reihe nützlicher Methoden, darunter:
Dies macht genau das, wonach Sie in einer Zeile gefragt haben. Wenn Sie die Dokumentation hier lesen, werden Sie feststellen, dass die vorgeschlagene Anpassung von
File.createTempFile("install", "dir")
normalerweise Sicherheitslücken verursacht.quelle
Wenn Sie zum Testen ein temporäres Verzeichnis benötigen und jUnit verwenden, löst
@Rule
zusammen mit:TemporaryFolder
Ihr Problem:Aus der Dokumentation :
Aktualisieren:
Wenn Sie JUnit Jupiter (Version 5.1.1 oder höher) verwenden, können Sie JUnit Pioneer verwenden, das JUnit 5 Extension Pack.
Aus der Projektdokumentation kopiert :
Weitere Informationen im JavaDoc und im JavaDoc von TempDirectory
Gradle:
Maven:
Update 2:
Die Annotation @TempDir wurde der JUnit Jupiter 5.4.0-Version als experimentelle Funktion hinzugefügt. Beispiel aus dem JUnit 5-Benutzerhandbuch kopiert :
quelle
Naiv geschriebener Code zur Lösung dieses Problems leidet unter den Rennbedingungen, einschließlich einiger der Antworten hier. In der Vergangenheit konnten Sie sorgfältig über die Rennbedingungen nachdenken und diese selbst schreiben oder eine Bibliothek eines Drittanbieters wie Google Guava verwenden (wie Spinas Antwort vorschlug). Oder Sie konnten fehlerhaften Code schreiben.
Aber ab JDK 7 gibt es gute Nachrichten! Die Java-Standardbibliothek selbst bietet jetzt eine ordnungsgemäß funktionierende (nicht rassige) Lösung für dieses Problem. Sie möchten java.nio.file.Files # createTempDirectory () . Aus der Dokumentation :
Dies behebt effektiv den peinlich alten Fehlerbericht im Sun-Bug-Tracker, der nach einer solchen Funktion gefragt hat.
quelle
Dies ist der Quellcode für Files.createTempDir () der Guava-Bibliothek. Es ist nirgends so komplex, wie Sie vielleicht denken:
Standardmäßig:
Siehe hier
quelle
Nicht verwenden,
deleteOnExit()
auch wenn Sie es später explizit löschen.Google 'deleteonexit is evil' für weitere Informationen, aber der Kern des Problems ist:
deleteOnExit()
Löscht nur für normale JVM-Abschaltungen, nicht für Abstürze oder das Beenden des JVM-Prozesses.deleteOnExit()
wird nur beim Herunterfahren der JVM gelöscht - nicht gut für lange laufende Serverprozesse, weil:Das Schlimmste von allen -
deleteOnExit()
verbraucht Speicher für jeden temporären Dateieintrag. Wenn Ihr Prozess monatelang ausgeführt wird oder in kurzer Zeit viele temporäre Dateien erstellt, verbrauchen Sie Speicher und geben ihn erst frei, wenn die JVM heruntergefahren wird.quelle
Ab Java 1.7
createTempDirectory(prefix, attrs)
undcreateTempDirectory(dir, prefix, attrs)
sind in enthaltenjava.nio.file.Files
Beispiel:
File tempDir = Files.createTempDirectory("foobar").toFile();
quelle
Folgendes habe ich für meinen eigenen Code beschlossen:
quelle
Nun, "createTempFile" erstellt die Datei tatsächlich. Warum also nicht zuerst löschen und dann das mkdir darauf ausführen?
quelle
Dieser Code sollte einigermaßen gut funktionieren:
quelle
Wie in dieser RFE und ihren Kommentaren erläutert , können Sie
tempDir.delete()
zuerst anrufen . Oder Sie können dortSystem.getProperty("java.io.tmpdir")
ein Verzeichnis verwenden und erstellen. In jedem Fall sollten Sie daran denken, anzurufentempDir.deleteOnExit()
, da sonst die Datei nicht gelöscht wird, wenn Sie fertig sind.quelle
Nur zur Vervollständigung ist dies der Code aus der Google Guava-Bibliothek. Es ist nicht mein Code, aber ich denke, es ist wertvoll, ihn hier in diesem Thread zu zeigen.
quelle
Ich habe das gleiche Problem, daher ist dies nur eine weitere Antwort für diejenigen, die interessiert sind, und es ähnelt einer der oben genannten:
Und für meine Anwendung habe ich beschlossen, eine Option hinzuzufügen, um die Temperatur beim Beenden zu löschen, also habe ich einen Shutdown-Hook hinzugefügt:
Die Methode löschen Sie alle subdirs und Dateien vor dem Löschen von Temp , ohne die Aufrufhierarchie verwendet (die völlig optional ist und man könnte es mit Rekursion an dieser Stelle tun), aber ich möchte auf der sicheren Seite sein.
quelle
Wie Sie in den anderen Antworten sehen können, ist kein Standardansatz entstanden. Daher haben Sie bereits Apache Commons erwähnt. Ich schlage den folgenden Ansatz mit FileUtils von Apache Commons IO vor :
Dies wird bevorzugt, da Apache die Bibliothek gemeinsam nutzt, die dem angeforderten "Standard" am nächsten kommt und sowohl mit JDK 7 als auch mit älteren Versionen funktioniert. Dies gibt auch eine "alte" Dateiinstanz (die streambasiert ist) und keine "neue" Pfadinstanz zurück (die pufferbasiert ist und das Ergebnis der getTemporaryDirectory () -Methode von JDK7 wäre) -> Daher wird zurückgegeben, was die meisten Benutzer wann benötigen Sie möchten ein temporäres Verzeichnis erstellen.
quelle
Ich mag die mehrfachen Versuche, einen eindeutigen Namen zu erstellen, aber selbst diese Lösung schließt eine Rennbedingung nicht aus. Ein anderer Prozess kann nach dem Test für
exists()
und demif(newTempDir.mkdirs())
Methodenaufruf einspringen. Ich habe keine Ahnung, wie ich dies vollständig sicher machen kann, ohne auf nativen Code zurückzugreifen, von dem ich annehme, dass er darin vergraben istFile.createTempFile()
.quelle
Vor Java 7 konnten Sie auch:
quelle
Versuchen Sie dieses kleine Beispiel:
Code:
Importe:
java.io.IOException
java.nio.file.Files
java.nio.file.Path
Konsolenausgabe auf Windows-Computern:
C: \ Benutzer \ Benutzername \ AppData \ Local \ Temp \ tmpDir2908538301081367877
Kommentar:
Files.createTempDirectory generiert atomatisch eine eindeutige ID - 2908538301081367877.
Hinweis:
Lesen Sie Folgendes, um Verzeichnisse rekursiv zu löschen:
Löschen Sie Verzeichnisse rekursiv in Java
quelle
Die Verwendung von
File#createTempFile
unddelete
zum Erstellen eines eindeutigen Namens für das Verzeichnis scheint in Ordnung zu sein. Sie sollten ein hinzufügenShutdownHook
, um das Verzeichnis (rekursiv) beim Herunterfahren von JVM zu löschen.quelle