保存到文件时如何确保数据不会被破坏?
我对C#比较新,所以请耐心等待。
我正在编写一个需要可靠的业务应用程序(在C#,.NET 4中)。 数据将存储在文件中。 文件将被定期修改(重写),因此我担心某些事情可能出错(掉电,应用程序被杀死,系统冻结……),同时保存数据(我认为)会导致文件损坏。 我知道没有保存的数据会丢失,但我不能丢失已保存的数据(因为损坏或……)。
我的想法是每个文件有2个版本,每次都重写最旧的文件。 然后,如果我的应用程序意外结束,至少有一个文件应该仍然有效。
这是一个好方法吗? 还有什么我能做的吗? (数据库不是一个选项)
谢谢你的时间和答案。
许多程序使用这种方法,但通常,它们会执行更多副本,以避免人为错误。
例如,Cadsoft Eagle(用于设计电路和印刷电路板的程序)最多可以为同一个文件创建9个备份副本,称之为file.b#1 … file.b#9
您可以采取的另一项措施是强制安全:散列:在文件末尾添加类似CRC32或MD5的散列。 打开它时,检查CRC或MD5,如果它们不匹配,则文件已损坏。 这也将强制您意外或按目的尝试使用其他程序修改您的文件。 这也将为您提供一种方法来了解硬盘驱动器或USB磁盘是否已损坏。
当然,保存文件操作越快,丢失数据的风险就越小,但您无法确定在写入期间或之后不会发生任何事情。
考虑到硬盘驱动器,USB驱动器和Windows操作系统都使用缓存,这意味着,如果你完成写入数据可能是操作系统或磁盘本身仍然没有物理写入磁盘。
你可以做的另一件事,保存到一个临时文件,如果一切正常你将文件移动到真正的目标文件夹,这将减少半文件的风险。
您可以将所有这些技术混合在一起。
您可以使用以下“安全文件写入”技术,而不是“始终写入最旧的”。
(假设您希望最终将数据保存到foo.data
,并且具有该名称的文件包含先前的有效版本。)
- 将新数据写入
foo.data.new
- 将
foo.data
重命名为foo.data.old
- 将
foo.data.new
重命名为foo.data
- 删除
foo.data.old
在任何时候你总是至少有一个有效的文件,你可以知道哪个是从文件名中读取的文件。 假设您的文件系统primefaces地处理重命名和删除操作。
- 如果存在
foo.data
和foo.data.new
,请加载foo.data
;foo.data.new
可能会被破坏(例如写入期间断电) - 如果存在
foo.data.old
和foo.data.new
,两者都应该是有效的,但事后很快就会死掉 – 你可能想要加载foo.data.old
版本 - 如果存在
foo.data
和foo.data.old
,那么foo.data
应该没问题,但是又出现了问题,或者可能无法删除文件。
或者,只需总是写入一个新文件,包括某种单调增加的计数器 – 这样你就不会因为写错而丢失任何数据。 最好的方法取决于你写的是什么。
您也可以使用File.Replace
,它基本上为您执行最后三个步骤。 (如果您不想保留备份,则传入null
作为备份名称。)
原则上有两种流行的方法:
- 使您的文件格式基于日志,即不要在通常的保存情况下覆盖,只需在最后添加更改或最新版本。
要么
- 写入新文件,将旧文件重命名为备份,并将新文件重命名为其位置。
第一个让你(开始)更多的开发工作,但是如果你保存对大文件的小改动(用于执行此AFAIK的Word),还具有使保存更快的优点。