c#文件移动和覆盖

时间:2012-01-08 08:53:27

标签: c# multithreading race-condition ioexception

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

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文件,但只有一个只读取此文件,没有写入操作。我使用锁来保护竞争条件。不知道为什么会这样。

UPDATE :即使visual c#debugger向我显示此异常,查看包含这些文件的目录,我看到没有sidetapedata.txt文件但是有一个sidetapedata2.txt文件!

UPDATE2 :此外,仅当sidetapedata.txtsidetapedata2.txt都为空时才会出现此行为

4 个答案:

答案 0 :(得分:8)

不确定为什么会发生这种情况,除非Delete调用在文件系统中触发了某些事件,这意味着在调用返回之后,它不会实际删除。一些选择:

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

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

答案 1 :(得分:3)

我不确定.NET是否相同,但根据win32 DeleteFile api引用:

  

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

因此,在调用Delete返回和Windows关闭文件的最后一个句柄之间可能存在一个时间窗口。看起来你在这段时间内正在调用Move。

答案 2 :(得分:1)

在 .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

答案 3 :(得分:0)

根据此answer:将FileStreamFileShare

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