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

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

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


当前回答

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

最好的方法是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.
}

其他回答

你可以使用我的库来访问多个应用程序中的文件。

您可以从nuget: install - package Xabe安装它。FileLock

如果你想了解更多信息,请检查 https://github.com/tomaszzmuda/Xabe.FileLock

ILock fileLock = new FileLock(file);
if(fileLock.Acquire(TimeSpan.FromSeconds(15), true))
{
    using(fileLock)
    {
        // file operations here
    }
}

fileLock。Acquire方法仅当可以锁定该对象的文件独占时才返回true。 但是上传文件的应用程序也必须在文件锁中进行上传。 如果对象不可访问,方法返回false。

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

最好的方法是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.
}

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

您可以返回一个任务,它会在流可用时立即提供给您。这是一个简化的解决方案,但却是一个很好的起点。是线程安全的。

private async Task<Stream> GetStreamAsync()
{
    try
    {
        return new FileStream("sample.mp3", FileMode.Open, FileAccess.Write);
    }
    catch (IOException)
    {
        await Task.Delay(TimeSpan.FromSeconds(1));
        return await GetStreamAsync();
    }
}

你可以像往常一样使用这个流:

using (var stream = await FileStreamGetter.GetStreamAsync())
{
    Console.WriteLine(stream.Length);
}

我最近遇到了这个问题,找到了这个: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.");
}