Java File.renameTo()
ist problematisch, besonders unter Windows, wie es scheint. Wie in der API-Dokumentation angegeben ,
Viele Aspekte des Verhaltens dieser Methode sind von Natur aus plattformabhängig: Der Umbenennungsvorgang kann eine Datei möglicherweise nicht von einem Dateisystem in ein anderes verschieben, ist möglicherweise nicht atomar und erfolgreich, wenn eine Datei mit dem abstrakten Zielpfadnamen erstellt wird ist bereits vorhanden. Der Rückgabewert sollte immer überprüft werden, um sicherzustellen, dass der Umbenennungsvorgang erfolgreich war.
In meinem Fall muss ich im Rahmen eines Upgrade-Vorgangs ein Verzeichnis verschieben (umbenennen), das möglicherweise Gigabyte an Daten enthält (viele Unterverzeichnisse und Dateien unterschiedlicher Größe). Das Verschieben erfolgt immer innerhalb derselben Partition / Laufwerk, sodass nicht wirklich alle Dateien auf der Festplatte physisch verschoben werden müssen.
Es sollten keine Dateisperren für den Inhalt des zu verschiebenden Verzeichnisses vorhanden sein, aber dennoch erledigt renameTo () häufig seine Aufgabe nicht und gibt false zurück. (Ich vermute nur, dass einige Dateisperren unter Windows möglicherweise etwas willkürlich ablaufen.)
Derzeit habe ich eine Fallback-Methode, die das Kopieren und Löschen verwendet, aber das ist zum Kotzen, da es je nach Größe des Ordners viel Zeit in Anspruch nehmen kann. Ich denke auch darüber nach, einfach die Tatsache zu dokumentieren, dass der Benutzer den Ordner manuell verschieben kann, um möglicherweise stundenlanges Warten zu vermeiden. Aber der richtige Weg wäre offensichtlich etwas Automatisches und Schnelles.
Meine Frage ist also, ob Sie einen alternativen, zuverlässigen Ansatz kennen, um mit Java unter Windows schnell zu verschieben / umzubenennen , entweder mit einfachem JDK oder einer externen Bibliothek. Oder wenn Sie eine einfache Möglichkeit kennen, Dateisperren für einen bestimmten Ordner und den gesamten Inhalt (möglicherweise Tausende einzelner Dateien) zu erkennen und aufzuheben , ist dies ebenfalls in Ordnung.
Bearbeiten : In diesem speziellen Fall scheinen wir davongekommen zu sein, indem wir nur renameTo()
ein paar weitere Dinge berücksichtigt haben. siehe diese Antwort .
Antworten:
Siehe auch die
Files.move()
Methode in JDK 7.Ein Beispiel:
quelle
Für das, was es wert ist, einige weitere Begriffe:
Unter Windows
renameTo()
scheint dies fehlzuschlagen, wenn das Zielverzeichnis vorhanden ist, auch wenn es leer ist. Dies überraschte mich, als ich es unter Linux versucht hatte, wo esrenameTo()
erfolgreich war, wenn das Ziel existierte, solange es leer war.(Natürlich hätte ich nicht annehmen sollen, dass so etwas plattformübergreifend gleich funktioniert. Genau davor warnt der Javadoc.)
Wenn Sie den Verdacht haben, dass einige Dateisperren bestehen bleiben, kann es hilfreich sein , ein wenig zu warten, bevor das Verschieben / Umbenennen erfolgt . (An einer Stelle in unserem Installationsprogramm / Upgrader haben wir für etwa 10 Sekunden eine "Schlaf" -Aktion und einen unbestimmten Fortschrittsbalken hinzugefügt, da möglicherweise ein Dienst an einigen Dateien hängt.) Führen Sie möglicherweise sogar einen einfachen Wiederholungsmechanismus durch, der dies versucht
renameTo()
und dann eine Zeitspanne wartet (die möglicherweise allmählich zunimmt), bis der Vorgang erfolgreich ist oder eine Zeitüberschreitung erreicht ist.In meinem Fall scheinen die meisten Probleme durch Berücksichtigung der beiden oben genannten Punkte gelöst worden zu sein, sodass wir schließlich keinen nativen Kernel-Aufruf oder ähnliches durchführen müssen.
quelle
In dem ursprünglichen Beitrag wurde "ein alternativer, zuverlässiger Ansatz zum schnellen Verschieben / Umbenennen mit Java unter Windows, entweder mit einfachem JDK oder einer externen Bibliothek", angefordert.
Eine weitere Option, die hier noch nicht erwähnt wurde, ist Version 1.3.2 oder höher der Bibliothek apache.commons.io , die FileUtils.moveFile () enthält .
Es wird eine IOException ausgelöst, anstatt bei einem Fehler boolean false zurückzugeben.
Siehe auch die Antwort von big lep in diesem anderen Thread .
quelle
java.nio.file.Path.moveTo()
In meinem Fall schien es sich um ein totes Objekt in meiner eigenen Anwendung zu handeln, das diese Datei im Griff hatte. Diese Lösung hat also bei mir funktioniert:
Vorteil: Es ist ziemlich schnell, da es kein Thread.sleep () mit einer bestimmten fest codierten Zeit gibt.
Nachteil: Diese Grenze von 20 ist eine fest codierte Zahl. In all meinen Tests ist i = 1 genug. Aber um sicher zu sein, habe ich es mit 20 verlassen.
quelle
Ich weiß, dass dies ein wenig hackig erscheint, aber für das, wofür ich es gebraucht habe, scheinen gepufferte Leser und Autoren kein Problem damit zu haben, die Dateien zu erstellen.
Funktioniert gut für kleine Textdateien als Teil eines Parsers. Stellen Sie nur sicher, dass oldName und newName vollständige Pfade zu den Dateispeicherorten sind.
Prost Kactus
quelle
Der folgende Code ist KEINE 'Alternative', hat aber in Windows- und Linux-Umgebungen zuverlässig funktioniert:
quelle
Unter Windows benutze ich
Runtime.getRuntime().exec("cmd \\c ")
und dann die Befehlszeilen-Umbenennungsfunktion, um Dateien tatsächlich umzubenennen. Es ist viel flexibler, z. B. wenn Sie die Erweiterung aller txt-Dateien in einem Verzeichnis umbenennen möchten, schreiben Sie dies einfach in den Ausgabestream:benenne * .txt * .bak um
Ich weiß, dass es keine gute Lösung ist, aber anscheinend hat es bei mir immer funktioniert, viel besser als der Java-Inline-Support.
quelle
Warum nicht....
funktioniert auf nwindows 7, macht nichts, wenn existiveFile nicht existiert, könnte aber offensichtlich besser instrumentiert werden, um dies zu beheben.
quelle
Ich hatte ein ähnliches Problem. Die Datei wurde unter Windows kopiert, funktionierte aber unter Linux gut. Ich habe das Problem behoben, indem ich den geöffneten fileInputStream geschlossen habe, bevor ich renameTo () aufgerufen habe. Getestet unter Windows XP.
quelle
In meinem Fall befand sich der Fehler im Pfad des übergeordneten Verzeichnisses. Vielleicht ein Fehler, ich musste den Teilstring verwenden, um einen korrekten Pfad zu erhalten.
quelle
Ich weiß, dass es scheiße ist, aber eine Alternative besteht darin, ein Bat-Skript zu erstellen, das etwas Einfaches wie "SUCCESS" oder "ERROR" ausgibt, es aufzurufen, auf die Ausführung zu warten und dann seine Ergebnisse zu überprüfen.
Runtime.getRuntime (). Exec ("cmd / c start test.bat");
Dieser Thread kann interessant sein. Überprüfen Sie auch die Process-Klasse, wie die Konsolenausgabe eines anderen Prozesses gelesen wird.
quelle
Sie können Robocopy versuchen . Dies ist nicht gerade "Umbenennen", aber es ist sehr zuverlässig.
quelle
Um eine Datei zu verschieben / umzubenennen, können Sie folgende Funktion verwenden:
Es ist in kernel32.dll definiert.
quelle
Das Obige ist der einfache Code. Ich habe unter Windows 7 getestet und funktioniert einwandfrei.
quelle