2011-10-31 109 views
2

我對C#比較新,所以請耐心等待。如何確保數據在保存到文件時不會損壞?

我正在寫一個需要可靠的業務應用程序(在C#中,.NET 4)。數據將存儲在文件中。文件會被定期修改(重寫),因此恐怕會出現問題(電源丟失,應用程序死機,系統死機......),同時保存會(我認爲)會導致文件損壞的數據。我知道沒有保存的數據會丟失,但我不能丟失已經保存的數據(因爲腐敗或...)。

我的想法是每個文件有2個版本,每次重寫最舊的文件。那麼,如果我的應用程序意外結束,至少有一個文件應該仍然有效。

這是一個好方法嗎?還有什麼我可以做的嗎? (數據庫不是一個選項)

謝謝你的時間和答案。

+1

出於好奇,爲什麼數據庫不是一個選項? –

+0

你如何更新這些文件?添加一行,添加字節?更新的頻率是多少? – esskar

+0

文件將被完全重寫,但只有一些部分會改變。文件相對較小(應小於1MB)。有些文件每天只有幾個時間,其他文件平均每5-10分鐘。 – Ben

回答

2

很多程序都使用這種方法,但通常情況下,他們會做更多的副本,以避免人爲錯誤。

例如,CADSOFT鷹(用於設計電路和印刷電路板的節目)做到同一文件的9個備份副本,稱他們file.b#1 ...#file.b 9

你可以做的另一件事情是強制執行安全措施:散列:在文件末尾追加一個像CRC32或MD5的散列。 當您打開它時,您檢查CRC或MD5,如果它們不匹配,則文件已損壞。 這也將強制你從意外或目的的人嘗試修改你的文件與另一個程序。 這也將讓你知道硬盤驅動器或USB磁盤是否損壞。

當然,保存文件操作的速度越快,丟失數據的風險就越小,但您無法確定在寫入過程中或寫入後會發生什麼。

考慮到硬盤驅動器,USB驅動器和Windows操作系統都使用緩存,也就是說,如果您完成寫入數據可能是操作系統或磁盤本身仍然沒有物理寫入磁盤。

你可以做的另一件事,保存到臨時文件,如果一切正常,你將文件移動到真正的目標文件夾,這將減少半文件的風險。

您可以將所有這些技術混合在一起。

+1

我通常會遵循這條路線,可能會添加重命名過去版本的邏輯,以便file.b#1始終是最新的副本。 – KeithS

+0

是的,這正是Eagle所做的。它還會刪除最舊的文件,並保留最多9個備份文件。你可以改變這一點。 –

+0

@SalvatorePreviti但是沒有更可靠的方法嗎?像Microsoft Visual Studio如何在沒有這種方法的情況下保存源代碼文件的編輯,並且立即將更改提交到磁盤? (至少在MS Visual Studio的Ctrl + S操作過程中,當突然斷電時,我還沒有遇到有人大聲說他得到損壞的源代碼文件)。現在我特別關注*立即*每次立即將文件寫入磁盤時提交更改。至少我知道即使數據庫引擎也將文件保存到磁盤。 –

7

,而不是「永遠寫入歷史最悠久的」您可以使用「安全文件寫入」技術:

(假設你要結束了數據保存到foo.data,並與該名稱的文件包含以前有效版本。)

  • 新數據寫入foo.data.new
  • 重命名foo.datafoo.data.old
  • 重命名foo.data.newfoo.data
  • 刪除foo.data.old

在任何時候你總是至少一個有效的文件,你可以告訴哪一個閱讀ju st來自文件名。這是假設你的文件系統當然會以原子方式處理重命名和刪除操作。

  • 如果foo.datafoo.data.new存在,負載foo.data; foo.data.new可能被打破(寫期間如斷電)
  • 如果foo.data.oldfoo.data.new存在,兩者都應該是有效的,但有些事去世不久之後 - 你可能要加載的foo.data.old版本反正
  • 如果foo.datafoo.data.old存在,那麼foo.data應該沒問題,但又出現了問題,或者文件可能無法刪除。

或者,乾脆總是寫入到一個新的文件,其中包括某種形式的單調遞增計數器的 - 這樣你永遠不會丟失任何數據,由於惡劣的寫入。最好的方法取決於你在寫什麼。

您也可以使用File.Replace這一點,基本上執行最後三個步驟你。 (在null通作備份名稱,如果你不想保留備份。)

+0

理論上,這應該足夠了,但在文件寫入時,由於操作系統緩存不實際。我已經實現了這個方法,並且看到.data和.data.old文件都被破壞了。更多關於這個問題:http://stackoverflow.com/questions/383324/how-to-ensure-all-data-has-been-physically-written-to-disk –

+0

值得注意的是添加一個關於文件的部分。替換這個答案?它爲你做了很多這方面的工作,並且據我所知,從ReplaceFile API文檔中,實際的數據交換既可以工作,也可以不工作 - 目標文件數據永遠不會被寫入一半或類似的東西。 –

+0

@MikeMarynowski:天哪,我以前從來沒有見過。是的,會添加一個註釋。 –

0

原則上有兩種流行的方法是:

  • 使你的文件格式的日誌爲基礎的,即做在通常的保存情況下不覆蓋,只是在最後追加更改或最新版本。

  • 寫入到一個新的文件,重命名舊文件的備份和新的文件重命名爲它的位置。

第一次爲您留下更多的開發工作,但如果您保存對大文件(Word用於執行此操作的AFAIK)的較小更改,則會使保存更快。

+0

如果只有一個文件在運行,基於日誌的寫入仍然會導致文件損壞。斷電等可能中斷實際的文件寫入,同時附加更改,這將導致沒有有效的EOF。 – KeithS

+0

在哪一點直到最新更改的所有數據都有效? – themel

+0

但是你(或者說,電腦)不知道有多少數據是有效的。電腦可能甚至不知道有多少數據是文件的一部分。 – KeithS

相關問題