Solange Sie die Datei nicht über Dateisystemgrenzen hinweg verschieben, sollte der Vorgang sicher sein. Dies ist auf den Mechanismus zurückzuführen, wie »Bewegen« tatsächlich durchgeführt wird.
Wenn Sie mv
eine Datei auf demselben Dateisystem haben, wird die Datei nicht wirklich berührt, sondern nur der Dateisystemeintrag wird geändert.
$ mv foo bar
macht eigentlich sowas
$ ln foo bar
$ rm foo
Dies würde einen schaffen harten Link (ein zweiter Verzeichniseintrag) für die Datei (eigentlich die Inode wies nach Dateisystemeintrag) foo
genannt bar
und das Entfernen foo
Eintrag. Da es jetzt beim Entfernen foo
einen zweiten Dateisystemeintrag gibt, der auf foo
den Inode verweist , werden durch das Entfernen des alten Eintrags foo
tatsächlich keine Blöcke entfernt, die zum Inode gehören.
Ihr Programm würde die Datei trotzdem gerne anhängen, da sein offenes Dateihandle auf den Inode der Datei und nicht auf den Dateisystemeintrag verweist.
Hinweis: Wenn Ihr Programm die Datei zwischen den Schreibvorgängen schließt und erneut öffnet, wird am Ende eine neue Datei mit dem alten Dateisystemeintrag erstellt!
Dateisystemübergreifende Verschiebungen:
Wenn Sie die Datei über Dateisystemgrenzen hinweg verschieben, werden die Dinge hässlich. In diesem Fall können Sie nicht garantieren, dass Ihre Datei konsistent bleibt, da mv
dies tatsächlich der Fall wäre
- Erstellen Sie eine neue Datei auf dem Zieldateisystem
- Kopieren Sie den Inhalt der alten Datei in die neue Datei
- entferne die alte Datei
oder
$ cp /path/to/foo /path/to/bar
$ rm /path/to/foo
bzw.
$ touch /path/to/bar
$ cat < /path/to/foo > /path/to/bar
$ rm /path/to/foo
Je nachdem, ob der Kopiervorgang während des Schreibens Ihrer Anwendung das Dateiende erreicht, kann es vorkommen, dass die neue Datei nur eine halbe Zeile enthält.
Wenn Ihre Anwendung die alte Datei nicht schließt und erneut öffnet, wird weiterhin in die alte Datei geschrieben, auch wenn sie gelöscht zu sein scheint: Der Kernel weiß, welche Dateien geöffnet sind, und obwohl der Dateisystemeintrag gelöscht wird, wird er gelöscht Löscht den Inode und die zugehörigen Blöcke der alten Datei erst, wenn die Anwendung das geöffnete Datei-Handle schließt.
rename()
Systemaufruf. Die ursprüngliche Version von hat alsomv
tatsächlich aufgerufenlink()
, um den festen Link zu erstellen, und anschließendunlink()
den ursprünglichen Namen zu entfernen.rename()
wurde in FreeBSD hinzugefügt, um dies atomar im Kernel zu implementieren.file-system borders
?Da Sie sagen, dass Sie node.js verwenden, gehe ich davon aus, dass Sie
fs.rename()
(oderfs.renameSync()
) verwenden, um die Dateien umzubenennen. Es ist dokumentiert, dass diese node.js-Methode den Systemaufruf rename (2) verwendet, der die Datei selbst in keiner Weise berührt, sondern lediglich den Namen ändert, unter dem sie im Dateisystem aufgeführt ist:Beachten Sie insbesondere den zuletzt genannten Satz, der besagt, dass alle geöffneten Dateideskriptoren (wie sie Ihr Programm zum Schreiben in die Datei verwenden würde) auch nach dem Umbenennen weiterhin darauf verweisen. Auf diese Weise gehen auch dann keine Daten verloren oder werden beschädigt, wenn die Datei umbenannt wird, während gleichzeitig darauf geschrieben wird.
Wie Andreas Weise in seiner Antwort festhält , funktioniert der Systemaufruf rename (2) (und damit
fs.rename()
in node.js) nicht über Dateisystemgrenzen hinweg. Daher schlägt der Versuch, eine Datei auf diese Weise in ein anderes Dateisystem zu verschieben, einfach fehl.Der Unix-
mv
Befehl versucht, diese Einschränkung auszublenden, indem er den Fehler erkennt und stattdessen die Datei verschiebt, indem er ihren Inhalt in eine neue Datei kopiert und das Original löscht. Leider besteht beim Verschieben von Dateien die Gefahr eines Datenverlusts, wenn die Datei während des Schreibens verschoben wird. Wenn Sie also Dateien, in die möglicherweise gleichzeitig geschrieben wird, sicher umbenennen möchten, sollten Sie nicht verwendenmv
(oder zumindest sicherstellen, dass sich der neue und der alte Pfad auf demselben Dateisystem befinden).quelle