【问题标题】:c# file move and overwrite [duplicate]c#文件移动和覆盖[重复]
【发布时间】:2012-02-05 06:40:22
【问题描述】:

我正在开发一个多线程应用程序。我的代码中有某处:

File.Delete(sidetapedata);
File.Move(sidetapedata2, sidetapedata); //sidetapedata and sidetapedata2 are two file paths that correspond to sidetapedata.txt and sidetaptdata2.txt in some directory.

第二行有时运行良好,有时会抛出 IOException

Cannot create a file when that file already exists.

还有一个线程正在访问sidetapedata 文件,但该线程仅读取此文件,没有写入操作。我正在使用锁来保护竞争条件。不知道为什么会这样。

更新:即使 Visual c# 调试器向我显示此异常,查看包含这些文件的目录,我看到没有 sidetapedata.txt 文件但有sidetapedata2.txt 文件!

UPDATE2:此外,这种行为仅在 sidetapedata.txtsidetapedata2.txt 均为空白时发生

【问题讨论】:

  • 在删除文件之前重命名文件,Windows/antivirus/etc 有时会在您要求 Windows 删除文件后片刻使文件“存在”。

标签: c# multithreading race-condition ioexception


【解决方案1】:

不知道为什么会发生这种情况,除非Delete 调用在文件系统中触发了某些事件,这意味着直到调用返回后不久它才实际上被删除。几个选项:

  • 您可以循环(在出错之前使用某种最大循环数)在尝试移动之前检查文件是否存在,如果删除后它仍然存在,则短暂休眠
  • 您可以使用File.Copy(sidetapedata, sidetapedata2, true)复制 而不是移动,然后删除源文件。不过,假设移动将通过简单的文件系统目录条目更改(而不是真正复制数据)来处理,这将降低效率
  • 您可以在目标文件上使用File.Move 而不是File.Delete 将其移动到其他无害的文件名,然后将其删除,希望MoveDelete 更具原子性。

怀疑线程在这里无关紧要 - 我建议您编写一个简短但完整的程序来验证它,这样您就可以排除它(并轻松测试变通方法)。

【讨论】:

  • 并不是说您的答案需要验证,但是您在删除后短时间内使用 Thread.Sleep 是对的,这为我解决了单线程应用程序中的类似问题。干杯。
【解决方案2】:

我不确定这对于 .NET 是否相同,但根据 win32 DeleteFile api 参考:

DeleteFile 函数在关闭时标记要删除的文件。因此,在文件的最后一个句柄关闭之前,不会发生文件删除。

所以在调用 Delete 返回和 Windows 关闭文件的最后一个句柄之间可能有一个时间窗口。您似乎在这段时间调用 Move。

【讨论】:

    【解决方案3】:

    在.NET Core 3.0及以后的版本中,可以调用Move(String, String, Boolean)设置参数overwrite为true,如果文件存在就会替换文件。

    https://docs.microsoft.com/en-us/dotnet/api/system.io.file.move?view=netcore-3.0

    【讨论】:

      【解决方案4】:

      根据这个answer:使用FileStreamFileShare

      FileStream fs = new FileStream(filename, FileMode.Open, FileAccess.ReadWrite, FileShare.None);
      

      【讨论】:

        猜你喜欢
        • 2016-07-17
        • 2011-11-17
        • 1970-01-01
        • 2012-12-09
        • 2023-04-09
        • 2017-12-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多