2013-03-04 40 views
3

我有一个应用程序写入更新磁盘文件,但我想尽可能确保以前版本的文件不被破坏。Clojure中的原子文件替换

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

(spit "myfile.txt" mystring) 

但是,如果PC(或Java程序)以书面的过程中死机,这有一个小破坏文件的机会。

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

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

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

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

谢谢!

+0

您是否在寻求一种更习惯的方式来执行相同的tempfile-rename-delete路径,或者更稳健的方法来维护文件结构的一致性? – Alex 2013-03-04 19:23:23

+0

当它完全正确的时候,我正在寻找保持文件结构一致性的最佳方式(我为一个项目构建一个小型的基于文件的数据库,并且希望确保我能够正确地记录文件。) – drcode 2013-03-04 19:55:24

+0

为什么删除tempfile?假设'。重命名“相当于'mv'源文件不应该存在。也不应该是'renameTo'?我在'java.io.File'中看不到'rename()'。 – 2013-03-05 03:00:38

回答

2

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

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

你需要写临时文件后的fsync()。 This question讨论从Java调用fsync()。

+0

谢谢。这看起来正是我需要知道的。让我等到更多反馈,然后再将您的答案标记为“正确” – drcode 2013-03-04 19:58:40

1

你给的例子是我的理解完全习惯和正确。如果上一次运行失败并且添加一些错误检测,我只会首先删除临时文件。

+0

谢谢Arthur,这真的很有帮助。但是,Rafal的类似但更复杂的响应在技术细节上占有很小的一部分。 – drcode 2013-03-04 20:03:11

1

根据您的意见反馈,我会建议你避免尝试推出自己的基于文件的数据库的基础上,一对夫妇的意见:

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

如果你在一个崩溃的情况下保持应用程序的数据的一致性真正感兴趣,那么我建议你看看嵌入可用的许多免费的数据库之一 - 您可以通过启动看着Berkely DB,HyperSQL或者更具Clojure风味的Datomic。

+0

嗨亚历克斯:我认为你对于几乎所有情况都绝对正确。然而,我认为我有一个罕见的用例,外部数据库是不切实际的。 (部分原因我不知道这个问题的答案正是因为我通常使用外部数据库,因为你推荐...)谢谢你的答案! – drcode 2013-03-04 20:16:55

+0

这就是我推荐嵌入式数据库的原因。例如,Berkely DB和HSQLDB都可以提供对文件支持数据库的进程内访问,而无需与外部进程进行通信。 – Alex 2013-03-04 20:30:12

+0

有意思......你说得对,那可能是我需要使用的东西。 – drcode 2013-03-04 21:05:01