3

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

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

(spit "myfile.txt" mystring)

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

一个更好的解决方案可能是这样写:

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

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

对 Clojure 文件 IO 有更深入了解的任何 Clojurians 是否对这是否是最佳方法有任何建议,或者是否有更好的方法可以在更新磁盘文件时最大限度地降低文件损坏的风险?

谢谢!

4

3 回答 3

2

这不是 Clojure 特有的;temp-rename-delete 方案不保证在 POSIX 标准下进行原子替换。这是由于写入重新排序的可能性 - 重命名可能会在临时写入之前到达物理磁盘,因此当在此时间窗口内发生电源故障时,会发生数据丢失。这不是纯粹理论上的可能性:

http://en.wikipedia.org/wiki/Ext4#Delayed_allocation_and_potential_data_loss

编写临时文件后,您需要一个 fsync() 。这个问题讨论了从 Java 调用 fsync() 。

于 2013-03-04T19:44:55.480 回答
1

你给出的例子在我看来是完全地道和正确的。如果之前的运行失败,我会先对 tempfile 进行删除并添加一些错误检测。

于 2013-03-04T19:34:04.907 回答
1

根据您的评论反馈,我建议您避免尝试推出自己的文件支持数据库,基于以下几点观察:

  • 文件系统中数据结构的持久存储在崩溃的情况下保持一致是一个难以解决的问题。很多真正聪明的人都花了很多时间思考这个问题。
  • 小型数据库往往会成长为大型数据库并随着时间的推移收集额外的功能。如果你自己动手,你会发现自己在项目过程中重新发明了轮子。

如果您真的对在发生崩溃时保持应用程序数据的一致性感兴趣,那么我建议您考虑嵌入许多可用的免费数据库之一 - 您可以从 Berkely DB、HyperSQL 开始,或者对于具有更多 Clo​​jure 风味的产品,Datomic。

于 2013-03-04T20:10:54.627 回答