Clojure中的原子文件替换

时间:2013-03-04 18:58:29

标签: file clojure atomic

我有一个应用程序写入更新磁盘文件,但我想尽可能确保该文件的先前版本不会被破坏。

更新文件最直接的方法当然是简单地写:

(spit "myfile.txt" mystring)

但是,如果PC(或java进程)在写入过程中死亡,则破坏文件的可能性很小。

更好的解决方案可能是写:

(do (spit "tempfile" mystring)
    (.rename (file "tempfile") "myfile.txt")
    (delete-file "tempfile"))

这使用java文件重命名功能,在大多数情况下,我收集的函数通常是在单个存储设备上执行的原子。

对Clojure文件IO有更深入了解的任何Clojurians是否有任何关于这是否是最佳方法的建议,或者更新磁盘文件时是否有更好的方法来最小化文件损坏的风险?

谢谢!

3 个答案:

答案 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。