Alternative zu File.deleteOnExit() in Java NIO?

Lesezeit: 7 Minuten

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?

  • 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

Benutzeravatar von Thunderforge
Donnerschmiede

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 OpenOptionswo 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.

  • Das ist eine gefährliche Antwort; DELETE_ON_CLOSE ist kein Ersatz für File.deleteOnExit() weil es Sie zwingt, den Ausgabestream so lange geöffnet zu lassen, wie Sie mit der Datei arbeiten möchten. Außerdem wird die Datei auf einigen Plattformen tatsächlich sofort gelöscht.

    – daiscog

    29. März 2017 um 10:21

  • @megaflop Das habe ich in meiner Antwort vermerkt DELETE_ON_CLOSE funktioniert insofern anders, als es „die Datei löscht, sobald der Stream geschlossen wird“, daher dachte ich, dass ich bereits klargestellt habe, dass es nicht auf die gleiche Weise funktioniert wie File.deleteOnExit(). Wenn Sie damit einverstanden sind, dass es sofort gelöscht wird (was in meinen Anwendungsfällen der Fall war), dann ist das ein guter Ersatz.

    – Donnerschmiede

    29. März 2017 um 17:28

  • Wenn es nicht dasselbe ist, ist die Frage nicht beantwortet.

    – Simon Jenkins

    11. März 2019 um 14:30 Uhr

João Vitor Verona Biazibettis Benutzeravatar
João Vitor Verona Biazibetti

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

  • +1 Es scheint, dass in der akzeptierten Antwort der Shutdown-Hook mit dem gekoppelt ist OutputStreamalso wenn Sie beabsichtigen, das zurückzugeben Path Anhand der Methode, mit der die temporäre Datei erstellt wird, werden Sie feststellen, dass Ihre temporäre Datei gelöscht wurde

    – dutoitns

    2. Mai 2016 um 8:11


Benutzeravatar von dimo414
dimo414

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_CLOSEWie 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 DeletePathsAtShutdownso wie ein remove() Funktion oder Unterstützung zum Löschen von Verzeichnissen.

1452700cookie-checkAlternative zu File.deleteOnExit() in Java NIO?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy