Desde que você não mova o arquivo pelas bordas do sistema de arquivos, a operação deve ser segura. Isto é devido ao mecanismo, como "mover" realmente é feito.
Se você mv
possui um arquivo no mesmo sistema de arquivos, o arquivo não é realmente tocado, mas apenas a entrada do sistema de arquivos é alterada.
$ mv foo bar
realmente faz algo como
$ ln foo bar
$ rm foo
Isso criaria um duro link (uma segunda entrada de diretório) para o arquivo (na verdade, o inode apontado por entrada do sistema de arquivos) foo
com o nome bar
e remover a foo
entrada. Como agora, ao remover foo
, existe uma segunda entrada do sistema de arquivos apontando para foo
o inode, remover a entrada antiga foo
na verdade não remove nenhum bloco pertencente ao inode.
Seu programa seria felizmente acrescentado ao arquivo de qualquer maneira, uma vez que seu identificador de arquivo aberto aponta para o inode do arquivo, não para a entrada do sistema de arquivos.
Nota: Se o seu programa fechar e reabrir o arquivo entre gravações, você poderá criar um novo arquivo com a entrada antiga do sistema de arquivos!
Movimentos cruzados do sistema de arquivos:
Se você mover o arquivo pelas bordas do sistema de arquivos, as coisas ficarão feias. Nesse caso, você não pode garantir que seu arquivo seja consistente, pois mv
isso realmente
- crie um novo arquivo no sistema de arquivos de destino
- copie o conteúdo do arquivo antigo para o novo arquivo
- remova o arquivo antigo
or
$ 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
Dependendo se a cópia atinge o final do arquivo durante a gravação do seu aplicativo, pode acontecer que você tenha apenas metade de uma linha no novo arquivo.
Além disso, se seu aplicativo não fechar e reabrir o arquivo antigo, ele continuará gravando no arquivo antigo, mesmo que pareça ser excluído: o kernel sabe quais arquivos estão abertos e, embora exclua a entrada do sistema de arquivos, não excluirá o inode do arquivo antigo e os blocos associados até que seu aplicativo feche seu identificador de arquivo aberto.
rename()
chamada de sistema. Portanto, a versão original demv
fato chamoulink()
para criar o link físico, seguido porunlink()
para remover o nome original.rename()
foi adicionado no FreeBSD, para implementar isso atomicamente no kernel.file-system borders
?Como você diz que está usando o node.js, presumo que você esteja usando
fs.rename()
(oufs.renameSync()
) para renomear os arquivos. Este método node.js está documentado para usar a chamada do sistema rename (2) , que não toca no arquivo em si de forma alguma, mas apenas altera o nome com o qual está listado no sistema de arquivos:Em particular, observe a última frase citada acima, que diz que qualquer descritor de arquivo aberto (como o seu programa usaria para gravar no arquivo) continuará apontando para ele, mesmo depois que ele for renomeado. Portanto, não haverá perda ou corrupção de dados, mesmo que o arquivo seja renomeado enquanto estiver sendo gravado simultaneamente.
Como Andreas Weise observa em sua resposta , a chamada do sistema renomear (2) (e, portanto,
fs.rename()
no node.js) não funcionará além dos limites do sistema de arquivos. Portanto, tentar mover um arquivo para um sistema de arquivos diferente dessa maneira simplesmente falhará.O
mv
comando Unix tenta ocultar essa limitação detectando o erro e, em vez disso, movendo o arquivo, copiando seu conteúdo para um novo arquivo e excluindo o original. Infelizmente, mover arquivos como este faz a perda de dados de risco se o arquivo é movido enquanto ele está sendo escrito. Assim, se você deseja renomear com segurança arquivos que podem ser gravados simultaneamente em, você deve não usarmv
(ou, pelo menos, você deve fazer absolutamente certo de que o novo e o velho caminho estão no mesmo sistema de arquivos).fonte