我正在用c#写一个程序,需要反复访问1个图像文件。大多数时候它是有效的,但如果我的计算机运行得很快,它会在文件保存回文件系统之前尝试访问该文件,并抛出一个错误:

文件正在被另一个进程使用

我想找到一个解决这个问题的方法,但我在谷歌上的所有搜索都只能通过使用异常处理来创建检查。这违背了我的宗教信仰,所以我想知道有没有更好的方法?


当前回答

我最近遇到了这个问题,找到了这个:https://learn.microsoft.com/en-us/dotnet/standard/io/handling-io-errors。

在这里,微软描述了以下检查IOException是否由于锁定文件导致的方法:

catch (IOException e) when ((e.HResult & 0x0000FFFF) == 32 ) {
    Console.WriteLine("There is a sharing violation.");
}

其他回答

我所知道的唯一方法是使用Win32独占锁API,这不是太快,但例子存在。

对于大多数人来说,一个简单的解决方案就是尝试/捕捉/睡眠循环。

也许您可以使用FileSystemWatcher并观察“已更改”事件。

我自己还没用过这个,但也许值得一试。如果对于这种情况,文件系统监控器显得有点重,那么我将使用try/catch/sleep循环。

您可能会遇到线程竞争条件,有文档示例将此用作安全漏洞。如果您检查文件是否可用,但随后尝试使用它,则可能会在此时抛出,恶意用户可能会使用它来强制和利用您的代码。

最好的方法是try catch / finally,它尝试获取文件句柄。

try
{
   using (Stream stream = new FileStream("MyFilename.txt", FileMode.Open))
   {
        // File/Stream manipulating code here
   }
} catch {
  //check here why it failed and ask user to retry if the file is in use.
}

我使用这个解决方案,但我有一个时间间隔,当我检查文件锁定与isfilellocked函数和当我打开文件。在这个时间跨度内,其他线程可以打开这个文件,所以我将得到IOException。

因此,我为此添加了额外的代码。在我的情况下,我想加载XDocument:

        XDocument xDoc = null;

        while (xDoc == null)
        {
            while (IsFileBeingUsed(_interactionXMLPath))
            {
                Logger.WriteMessage(Logger.LogPrioritet.Warning, "Deserialize can not open XML file. is being used by another process. wait...");
                Thread.Sleep(100);
            }
            try
            {
                xDoc = XDocument.Load(_interactionXMLPath);
            }
            catch
            {
                Logger.WriteMessage(Logger.LogPrioritet.Error, "Load working!!!!!");
            }
        }

你怎么看?我能改点东西吗?也许我没有使用IsFileBeingUsed函数在所有?

谢谢

尝试将文件移动/复制到临时目录。如果可以的话,它没有锁,您可以安全地在临时目录中工作而不需要锁。否则就在x秒内再移动一次。