2011-10-31 106 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

相关问题