System.IO.File.Delete()/ System.IO.File.Move()有时不起作用

DJA*_*DJA 5 c# move ioexception delete-file

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

这几乎在所有时间都在实验室和生产中使用.该程序在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()
Run Code Online (Sandbox Code Playgroud)

就好像在发出Move之前,Delete实际上没有发送到硬盘驱动器.

这种情况发生在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
    }
}
Run Code Online (Sandbox Code Playgroud)

谁看过这个吗?

Han*_*ant 13

您永远不能假设您可以删除文件并在多用户多任务操作系统上将其删除.从另一个应用程序或用户自己对该文件感兴趣,您还可以运行对文件感兴趣的服务.病毒扫描程序和搜索索引器是经典的麻烦制造者.

此类程序打开文件并尝试通过指定删除共享访问来最小化其影响.这在.NET中也可用,它是FileShare.Delete选项.有了该选项,Windows允许进程删除该文件,即使它已打开.它在内部标记为"删除待处理".该文件实际上并没有从文件系统中删除,它在File.Delete调用后仍然存在.任何试图打开该文件的人都会获得访问被拒绝错误.在文件对象的最后一个句柄关闭之前,文件实际上不会被删除.

您可以看到它的标题,这解释了为什么File.Delete成功但File.Move失败.你需要做的是File.Move文件,所以它有一个不同的名称. 然后重命名新文件,然后删除原始文件.您要做的第一件事就是删除带有重命名名称的可能的杂散副本,它可能因电源故障而被遗忘.

总结:

  1. 创建file.new
  2. 删除file.tmp
  3. 将file.xml重命名为file.tmp
  4. 将file.new重命名为file.xml
  5. 删除file.tmp

步骤5的失败并不重要.


Bek*_*pov 3

如何使用 Move.Copy 将 overwrite 设置为 true 以便覆盖您的应用程序状态,然后您可以删除您的临时状态?

您还可以附加到App_Exit事件并尝试执行干净关闭吗?