Winforms 程序需要将一些运行时信息保存到 XML 文件中。该文件有时可能有几百千字节大小。在 Beta 测试期间,我们发现一些用户会毫不犹豫地看似随机地终止进程,有时会导致文件写入一半并因此损坏。
因此,我们更改了算法以保存到临时文件,然后删除真实文件并进行移动。
我们的代码目前看起来像这样..
private void Save()
{
XmlTextWriter streamWriter = null;
try
{
streamWriter = new XmlTextWriter(xmlTempFilePath, System.Text.Encoding.UTF8);
XmlSerializer xmlSerializer = new XmlSerializer(typeof(MyCollection));
xmlSerializer.Serialize(streamWriter, myCollection);
if (streamWriter != null)
streamWriter.Close();
// Delete the original file
System.IO.File.Delete(xmlFilePath);
// Do a move over the top of the original file
System.IO.File.Move(xmlTempFilePath, xmlFilePath);
}
catch (System.Exception ex)
{
throw new InvalidOperationException("Could not save the xml file.", ex);
}
finally
{
if (streamWriter != null)
streamWriter.Close();
}
}
这在实验室和生产中几乎一直有效。该程序在 12 台计算机上运行,平均每 5 分钟调用一次该代码。我们每天大约会遇到一两次这样的异常:
System.InvalidOperationException:
Could not save the xml file.
---> System.IO.IOException: Cannot create a file when that file already exists.
at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
at System.IO.__Error.WinIOError()
at System.IO.File.Move(String sourceFileName, String destFileName)
at MyApp.MyNamespace.InternalSave()
就好像在发出移动之前实际上并未向硬盘发出删除。
Win7机器上会出现这种情况。
有几个问题:是否有一些概念Flush()
一个可以为整个磁盘操作系统做些什么?这是我的代码、.net、操作系统还是其他方面的错误吗?我应该放一些吗Thread.Sleep(x)
?也许我应该做一个File.Copy(src, dest, true)
?我应该写下面的代码吗? (但这看起来很愚蠢。)
while (System.IO.File.Exists(xmlFilePath))
{
System.IO.File.Delete(xmlFilePath);
}
// Do a move over the top of the main file
bool done = false;
while (!done)
{
try
{
System.IO.File.Move(xmlTempFilePath, xmlFilePath);
done = true;
}
catch (System.IO.IOException)
{
// let it loop
}
}
有没有人见过这个?