Mientras no mueva el archivo a través de los bordes del sistema de archivos, la operación debe ser segura. Esto se debe al mecanismo, cómo se realiza realmente el "movimiento".
Si tiene mv
un archivo en el mismo sistema de archivos, el archivo no se toca realmente, sino que solo se modifica la entrada del sistema de archivos.
$ mv foo bar
en realidad hace algo como
$ ln foo bar
$ rm foo
Esto crearía un enlace rígido (una segunda entrada de directorio) para el archivo (en realidad el inodo señalado por la entrada del sistema de archivos) foo
nombrado bar
y eliminaría la foo
entrada. Como ahora al eliminar foo
, hay una segunda entrada del sistema de archivos que apunta al foo
inodo de '', eliminar la entrada anterior foo
no elimina realmente ningún bloque que pertenezca al inodo.
De todos modos, su programa se agregaría al archivo, ya que su identificador de archivo abierto apunta al inodo del archivo, no a la entrada del sistema de archivos.
Nota: Si su programa cierra y vuelve a abrir el archivo entre escrituras, ¡terminaría teniendo un nuevo archivo creado con la entrada anterior del sistema de archivos!
Movimientos cruzados del sistema de archivos:
Si mueve el archivo a través de los bordes del sistema de archivos, las cosas se ponen feas. En este caso, no puede garantizar que su archivo se mantenga constante, ya mv
que en realidad
- crear un nuevo archivo en el sistema de archivos de destino
- copie el contenido del archivo antiguo al archivo nuevo
- eliminar el archivo antiguo
o
$ cp /path/to/foo /path/to/bar
$ rm /path/to/foo
resp.
$ touch /path/to/bar
$ cat < /path/to/foo > /path/to/bar
$ rm /path/to/foo
Dependiendo de si la copia llega al final del archivo durante la escritura de su aplicación, podría suceder que solo tenga la mitad de una línea en el nuevo archivo.
Además, si su aplicación no cierra y vuelve a abrir el archivo anterior, continuaría escribiendo en el archivo anterior, incluso si parece haber sido eliminado: el núcleo sabe qué archivos están abiertos y, aunque eliminaría la entrada del sistema de archivos, no eliminará el inodo del archivo antiguo y los bloques asociados hasta que su aplicación cierre su identificador de archivo abierto.
rename()
llamada al sistema. Entonces, la versión original demv
realmente llamólink()
para crear el enlace duro, seguido deunlink()
eliminar el nombre original.rename()
fue agregado en FreeBSD, para implementar esto atómicamente en el kernel.file-system borders
?Como dice que está usando node.js, supongo que estaría usando
fs.rename()
(ofs.renameSync()
) para cambiar el nombre de los archivos. Este método de node.js está documentado para usar la llamada al sistema rename (2) , que no toca el archivo en sí mismo de ninguna manera, sino que simplemente cambia el nombre con el que aparece en el sistema de archivos:En particular, tenga en cuenta la última oración citada anteriormente, que dice que cualquier descriptor de archivo abierto (como el que usaría su programa para escribir en el archivo) continuará apuntándolo incluso después de haber cambiado el nombre. Por lo tanto, no habrá pérdida de datos ni corrupción, incluso si se cambia el nombre del archivo mientras se escribe simultáneamente.
Como Andreas Weise señala en su respuesta , la llamada al sistema rename (2) (y, por lo tanto,
fs.rename()
en node.js) no funcionará a través de los límites del sistema de archivos. Por lo tanto, intentar mover un archivo a un sistema de archivos diferente de esta manera simplemente fallará.El
mv
comando Unix intenta ocultar esta limitación detectando el error y, en cambio, moviendo el archivo copiando su contenido a un nuevo archivo y eliminando el original. Desafortunadamente, mover archivos como este conlleva el riesgo de pérdida de datos si el archivo se mueve mientras se está escribiendo. Por lo tanto, si desea cambiar el nombre de forma segura archivos que se pueden escribir simultáneamente a, usted debe no usarmv
(o, al menos, debe estar absolutamente seguro de que el camino nuevo y viejo están en el mismo sistema de archivos).fuente