2013-03-04 71 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