如何使用C#安全地将数据保存到现有文件?

Jua*_*uan 13 c# io

如何安全地将数据保存到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);
Run Code Online (Sandbox Code Playgroud)

问题是,当我试图保存到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);
    }
}
Run Code Online (Sandbox Code Playgroud)

Player.Math.RandomDigits 这只是我创建的一个小函数,它创建了一个包含n个随机数字的字符串.

除非操作系统正在进行,否则我不会看到这会如何搞乱原始文件.它与Hans的答案非常接近,只是我首先将文件保存到临时文件中,这样,如果在序列化时出现问题,我不需要将文件重命名为原始名称,这也可能出错.请!如果你发现任何缺陷,请告诉我.

Meh*_*dad 7

我不确定这有多安全,但假设您的操作系统没有崩溃,请猜猜是什么?有一个应用程序:File.Replace

File.Replace(tempFile, fileName, backupFileName);
Run Code Online (Sandbox Code Playgroud)

我认为在危急情况下你真正需要的是交易 ; 只有这样才能保证不会丢失数据.看看这篇文章的.NET解决方案,但要注意它可能比简单的文件替换解决方案更难使用.