问题描述
我有一个编写用于更新磁盘文件的应用程序,但我想确保尽可能确保文件的先前版本不会损坏.
I have an app that writes that updates a disk file, but I want to make sure, as much as possible, that the previous version of the file doesn't get corrupted.
当然,更新文件的最直接方法是简单地编写:
The most straight forward way to update a file, of course, is to simply write:
(spit "myfile.txt" mystring)
但是,如果PC(或Java进程)在编写过程中死了,则损坏文件的可能性很小.
However, if the PC (or java process) dies in the middle of writing, this has a small chance of corrupting the file.
一个更好的解决方案可能是编写:
A better solution is probably to write:
(do (spit "tempfile" mystring)
(.rename (file "tempfile") "myfile.txt")
(delete-file "tempfile"))
这使用了Java文件重命名功能,在大多数情况下,当我在单个存储设备上执行该功能时,我收集的该文件通常是原子的.
This uses the java file rename function, which I gather is typically atomic when performed on a single storage device in most cases.
任何对Clojure文件IO有更深入了解的Clojurian都对这是否是最好的方法或者在更新磁盘文件时是否有更好的方法来最大程度地减小文件损坏的风险有任何建议吗?
Do any Clojurians with some deeper knowledge of Clojure file IO have any advice on whether this is the best approach, or if there's a better way to minimize the risk of file corruption when updating a disk file?
谢谢!
推荐答案
这并非特定于Clojure;临时重命名删除方案不能保证POSIX标准下的原子替换.这是由于可能会进行写入重新排序-重命名可能会在临时写入之前重命名到物理磁盘,因此,在此时间段内发生电源故障时,就会发生数据丢失.这不是纯粹的理论可能性:
This is not specific to Clojure; a temp-rename-delete scenario does not guarantee an atomic replace under the POSIX standard. This is due to the possibility of write reordering - the rename might get to the physical disk before the temp writes do, so when a power failure happens within this time window, data loss happens. This is not a purely theoretical possibility:
http://en.wikipedia.org/wiki/Ext4#Delayed_allocation_and_potential_data_loss
写入临时文件后,需要一个fsync(). 这个问题讨论了从Java调用fsync().
You need an fsync() after writing the temp file. This question discusses calling fsync() from Java.
这篇关于Clojure中的原子文件替换的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!