我有一个应用程序写入更新磁盘文件,但我想尽可能确保该文件的先前版本不会被破坏。
更新文件最直接的方法当然是简单地写:
(spit "myfile.txt" mystring)
但是,如果PC(或java进程)在写入过程中死亡,则破坏文件的可能性很小。
更好的解决方案可能是写:
(do (spit "tempfile" mystring)
(.rename (file "tempfile") "myfile.txt")
(delete-file "tempfile"))
这使用java文件重命名功能,在大多数情况下,我收集的函数通常是在单个存储设备上执行的原子。
对Clojure文件IO有更深入了解的任何Clojurians是否有任何关于这是否是最佳方法的建议,或者更新磁盘文件时是否有更好的方法来最小化文件损坏的风险?
谢谢!
答案 0 :(得分:2)
这不是特定的Clojure;临时重命名删除方案不保证POSIX标准下的原子替换。这是由于写入重新排序的可能性 - 重命名可能在临时写入之前到达物理磁盘,因此当在此时间窗口内发生电源故障时,会发生数据丢失。这不是纯理论上的可能性:
http://en.wikipedia.org/wiki/Ext4#Delayed_allocation_and_potential_data_loss
编写临时文件后需要fsync()。 This question讨论了从Java调用fsync()。
答案 1 :(得分:1)
你给出的例子是我的理解完全惯用和正确。如果上一次运行失败并添加一些错误检测,我会先对tempfile执行删除操作。
答案 2 :(得分:1)
根据您评论的反馈,我建议您根据以下几点观察,避免尝试推送自己的文件支持数据库:
如果您真的对在发生崩溃时保持应用程序数据的一致性感兴趣,那么我建议您考虑嵌入许多可用的免费数据库中的一个 - 您可以从查看Berkely开始DB,HyperSQL,或者具有更多Clojure风格的数据,Datomic。