如何在C#中安全地将数据保存到已存在的文件中?我有一些序列化为文件的数据,直接将其安全保存到文件中肯定不是个好主意,因为如果出现任何问题,文件会损坏,之前的版本也会丢失。
因此,这是我迄今为止所做的:
string tempFile = Path.GetTempFileName();
using (Stream tempFileStream = File.Open(tempFile, FileMode.Truncate))
{
SafeXmlSerializer xmlFormatter = new SafeXmlSerializer(typeof(Project));
xmlFormatter.Serialize(tempFileStream, Project);
}
if (File.Exists(fileName)) File.Delete(fileName);
File.Move(tempFile, fileName);
if (File.Exists(tempFile)) File.Delete(tempFile);
问题在于我试图保存到一个位于我的Dropbox中的文件时,有时会出现异常告诉我无法保存到已存在的文件。显然第一个File.Delete(fileName);
没有立即删除文件,而是稍等片刻才删除。因此,在File.Move(tempFile, fileName);
时出现了异常,因为该文件已经存在并且随后被删除,导致我的文件丢失。
我使用过其他带有Dropbox文件的应用程序,它们以某种方式设法避免出现问题。当我尝试保存到Dropbox文件夹中的文件时,有时会收到消息告诉我文件正在使用或类似的东西,但我从未遇到文件被删除的问题。
那么这里应该采用什么样的标准/最佳实践呢?
好的,在阅读所有答案后,我得出以下结论:
private string GetTempFileName(string dir)
{
string name = null;
int attempts = 0;
do
{
name = "temp_" + Player.Math.RandomDigits(10) + ".hsp";
attempts++;
if (attempts > 10) throw new Exception("Could not create temporary file.");
}
while (File.Exists(Path.Combine(dir, name)));
return name;
}
private void SaveProject(string fileName)
{
bool originalRenamed = false;
string tempNewFile = null;
string oldFileTempName = null;
try
{
tempNewFile = GetTempFileName(Path.GetDirectoryName(fileName));
using (Stream tempNewFileStream = File.Open(tempNewFile, FileMode.CreateNew))
{
SafeXmlSerializer xmlFormatter = new SafeXmlSerializer(typeof(Project));
xmlFormatter.Serialize(tempNewFileStream, Project);
}
if (File.Exists(fileName))
{
oldFileTempName = GetTempFileName(Path.GetDirectoryName(fileName));
File.Move(fileName, oldFileTempName);
originalRenamed = true;
}
File.Move(tempNewFile, fileName);
originalRenamed = false;
CurrentProjectPath = fileName;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
finally
{
if(tempNewFile != null) File.Delete(tempNewFile);
if (originalRenamed) MessageBox.Show("'" + fileName + "'" +
" have been corrupted or deleted in this operation.\n" +
"A backup copy have been created at '" + oldFileTempName + "'");
else if (oldFileTempName != null) File.Delete(oldFileTempName);
}
}
Player.Math.RandomDigits
是我编写的一个小函数,它会创建一个由n个随机数字组成的字符串。
我不认为这会破坏原始文件,除非操作系统出现问题。这与Hans的回答非常接近,只是我首先将文件保存到临时文件中,以便在序列化时出现问题时,我不需要将文件重命名回原始名称,这也可能出现问题。如果您发现任何缺陷,请告诉我!
File.Copy(tempFile, fileName, true);
,然后再使用File.Delete(tempFile);
呢? - user541686File.Copy
出现任何问题,我认为最坏的情况就是什么都不会发生,原始文件保持不变。当然,我的想法可能有误... - Juan