Java IO hat File.deleteOnExit()Dabei handelt es sich um eine Methode, die die aufgerufene Datei während der normalen Beendigung der JVM löscht. Ich habe festgestellt, dass dies zum Bereinigen temporärer Dateien sehr nützlich ist, insbesondere bei Komponententests.
Allerdings sehe ich in Java NIOs keine Methode mit demselben Namen Dateien Klasse. Ich bin mir bewusst, dass ich es kann path.toFile().deleteOnExit()
aber ich würde gerne wissen, ob es eine Alternative mit NIO gibt.
Gibt es eine Alternative? Wenn nicht, warum gibt es keinen?
Kurze Antwort
Sie können in Java NIO keine beliebigen Dateien löschen, aber Sie können das verwenden StandardOpenOption.DELETE_ON_CLOSE
beim Öffnen eines neuen Streams, wodurch die Datei gelöscht wird, sobald der Stream geschlossen wird, entweder durch Aufruf .close()
(einschließlich einer Try-with-Resources-Anweisung) oder die JVM wird beendet. Zum Beispiel:
Files.newOutputStream(Paths.get("Foo.tmp"), StandardOpenOption.DELETE_ON_CLOSE);
Lange Antwort
Nach langem Stöbern habe ich Java NIO gefunden tut Es gibt eine Möglichkeit, beim Beenden zu löschen, diese geht jedoch anders vor als Java I/O.
Zunächst einmal das Javadoc für Files.createTempFile()
beschreibt drei Möglichkeiten zum Löschen von Dateien:
Wo als verwendet Arbeitsdateien [sic]kann die resultierende Datei mit geöffnet werden DELETE_ON_CLOSE
Option, damit die Datei gelöscht wird, wenn die entsprechende Schließmethode aufgerufen wird. Alternativ a Shutdown-Hookoder der File.deleteOnExit()
Es kann ein Mechanismus zum automatischen Löschen der Datei verwendet werden.
Die letzte Wahl, File.deleteOnExit()
ist natürlich eine Java-I/O-Methode, die wir zu vermeiden versuchen. Ein Shutdown-Hook ist das, was hinter den Kulissen passiert, wenn Sie die oben genannte Methode aufrufen. Aber die DELETE_ON_CLOSE
Option ist reines Java NIO.
Anstatt beliebige Dateien zu löschen, geht Java NIO davon aus, dass Sie nur daran interessiert sind, Dateien zu löschen, die Sie tatsächlich öffnen. Daher sind Methoden, die einen neuen Stream erstellen, wie z Files.newOutputStream()
kann optional auch mehrere nehmen OpenOptions
wo Sie Eingaben vornehmen können StandardOpenOption.DELETE_ON_CLOSE
. Dadurch wird die Datei gelöscht, sobald der Stream geschlossen wird (entweder durch einen Aufruf von .close()
oder die JVM wird beendet).
Zum Beispiel:
Files.newOutputStream(Paths.get("Foo.tmp"), StandardOpenOption.DELETE_ON_CLOSE);
…löscht die mit dem Stream verknüpfte Datei, wenn der Stream geschlossen wird, entweder durch einen expliziten Aufruf von .close()
der Stream wird als Teil einer try-with-resources-Anweisung geschlossen oder die JVM wird beendet.
Aktualisieren: Auf einigen Betriebssystemen wie Linux, StandardOpenOption.DELETE_ON_CLOSE
löscht, sobald der OutputStream erstellt wird. Wenn Sie nur einen OutputStream benötigen, ist das möglicherweise immer noch in Ordnung. Weitere Informationen finden Sie unter DELETE_ON_CLOSE löscht Dateien vor dem Schließen unter Linux.
Deshalb fügt Java NIO gegenüber Java I/O neue Funktionen hinzu, indem Sie eine Datei löschen können, wenn Sie einen Stream schließen. Wenn dies eine ausreichend gute Alternative zum Löschen beim JVM-Beenden ist, können Sie dies in reinem Java NIO tun. Wenn nicht, müssen Sie sich auf Java-I/Os verlassen File.deleteOnExit()
oder ein Shutdown-Hook, um die Datei zu löschen.
Hinter den Kulissen, File.deleteOnExit()
werde einfach eine erstellen shutdown hook
über Runtime.addShutdownHook()
.
Dann können Sie dasselbe mit NIO tun:
Runtime.getRuntime().addShutdownHook(new Thread() {
public void run() {
Path path = ...;
Files.delete(path);
}
});
Ich würde kein Schuhanzieher empfehlen StandardOpenOption.DELETE_ON_CLOSE
in einen Ersatz für File.deleteOnExit()
. Wie in der Dokumentation erwähnt, ist es weder für allgemeine Zwecke gedacht, noch funktioniert es außerhalb trivialer Fälle wahrscheinlich ordnungsgemäß.
DELETE_ON_CLOSE
Wie der Name schon sagt, dient es dazu, eine Datei nach dem Schließen zu entfernen, um eine nicht mehr benötigte Ressource sofort zu bereinigen. Die Dokumentation für Files.createTempFile()
ist in diesem Punkt ähnlich klar, DELETE_ON_CLOSE
Kann für „Arbeitsdateien“ verwendet werden und wird nur benötigt, während die Datei geöffnet ist.
Der Files.createTempFile()
In den Dokumenten wird empfohlen, entweder direkt einen eigenen Shutdown-Hook zu schreiben oder ihn einfach weiter zu verwenden File.deleteOnExit()
. Trotz Ihres Wunsches, NIO zu verwenden, ist die Verwendung von NIO grundsätzlich nicht verkehrt File.deleteOnExit()
wenn Sie nur mit dem lokalen Dateisystem arbeiten. Wenn Sie das lokale Dateisystem nicht verwenden (oder nicht sicher sind, dass Sie es verwenden) und daher kippen verwenden File.deleteOnExit()
Es ist einfach genug, einen eigenen Shutdown-Hook zu schreiben einfach was File
tut:
public final class DeletePathsAtShutdown {
private static LinkedHashSet<Path> files = new LinkedHashSet<>();
static {
Runtime.getRuntime().addShutdownHook(
new Thread(DeletePathsAtShutdown::shutdownHook));
}
private static void shutdownHook() {
LinkedHashSet<Path> local;
synchronized {
local = paths;
paths = null;
}
ArrayList<Path> toBeDeleted = new ArrayList<>(theFiles);
Collections.reverse(toBeDeleted);
for (Path p : toBeDeleted) {
try {
Files.delete(p);
} catch (IOException | RuntimeException e) {
// do nothing - best-effort
}
}
}
public static synchronized void register(Path p) {
if (paths == null) {
throw new IllegalStateException("ShutdownHook already in progress.");
}
paths.add(p);
}
}
Sicherlich wäre es schön, wenn NIO einen ähnlichen Shutdown-Hook sofort mitliefern würde, aber sein Fehlen ist kein Grund, das falsche Tool für diese Aufgabe zu verwenden. Sie können auch weitere Funktionen hinzufügen DeletePathsAtShutdown
so wie ein remove()
Funktion oder Unterstützung zum Löschen von Verzeichnissen.
Was würde die NIO-Version anders oder besser machen? (Abgesehen vom Fallenlassen
.toFile()
aus der Anrufkette.)– Peter Lawrey
26. Februar 2015 um 20:24
@Thunderforge DataInputStream.readLine() war tatsächlich
@Deprecated
1998 ist es immer noch da. Welche Vorteile hat es, „komplett in NIO zu leben“?– Peter Lawrey
26. Februar 2015 um 20:48
@PeterLawrey Mir ist bewusst, dass Java dazu neigt, Dinge, die es veraltet, nicht zu entfernen (was mir aus Python bizarr vorkommt), aber eines Tages könnten sie es tun. Was „vollständig in NIO leben“ betrifft, wäre der Code einfacher zu verstehen, wenn er vollständig in NIO wäre, anstatt beides zu verwenden (insbesondere für jüngere Entwickler, die vielleicht mit NIO angefangen haben und IO noch nie zuvor verwendet hätten). Unabhängig davon, ob Sie mit der Begründung einverstanden sind oder nicht, würde ich dennoch gerne wissen, ob es eine Alternative gibt.
– Donnerschmiede
26. Februar 2015 um 20:58
@Thunderforge, der Punkt, den ich ansprechen wollte, ist, dass in Java das Hinzufügen von Dingen vermieden wird, es sei denn, es gibt einen zwingenden Grund, etwas zu tun. Jede Methode, die sie hinzufügen, wird sehr sorgfältig geprüft, und wenn alles, was sie bewirken würde, weitgehend mit einer vorhandenen Methode übereinstimmt, vermute ich, dass dies nicht der Fall sein wird.
– Peter Lawrey
26. Februar 2015 um 21:01 Uhr
„Vollständig in NIO zu leben“ ist kein Vorteil, sondern nur eine willkürliche, selbst auferlegte Einschränkung.
– Benutzer207421
26. Februar 2015 um 21:07 Uhr