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

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

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


当前回答

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

其他回答

更新了该解决方案的说明:使用FileAccess检查。对于只读文件,ReadWrite将失败,因此解决方案已修改为使用FileAccess.Read进行检查。

原: 在过去的几年里,我一直在使用这段代码,没有遇到过任何问题。

理解你在使用异常时的犹豫,但你不能总是避免它们:

protected virtual bool IsFileLocked(FileInfo file)
{
    try
    {
        using(FileStream stream = file.Open(FileMode.Open, FileAccess.Read, FileShare.None))
        {
            stream.Close();
        }
    }
    catch (IOException)
    {
        //the file is unavailable because it is:
        //still being written to
        //or being processed by another thread
        //or does not exist (has already been processed)
        return true;
    }

    //file is not locked
    return false;
}

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

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

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

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

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

除了工作3-liner,只是为了参考:如果你想要完整的信息-在微软开发中心有一个小项目:

https://code.msdn.microsoft.com/windowsapps/How-to-know-the-process-704839f4

现发现于: https://github.com/TacticalHorse/LockFinder/blob/master/LockFinder.cs

引言:

The C# sample code developed in .NET Framework 4.0 would help in finding out which is the process that is having a lock on a file. RmStartSession function which is included in rstrtmgr.dll has been used to create a restart manager session and according to the return result a new instance of Win32Exception object is created. After registering the resources to a Restart Manager session via RmRegisterRescources function, RmGetList function is invoked to check what are the applications are using a particular file by enumerating the RM_PROCESS_INFO array.

它通过连接到“重启管理器会话”来工作。

重启管理器使用向会话注册的资源列表 确定哪些应用程序和服务必须关闭并重新启动。 资源可以通过文件名、服务短名称或 描述正在运行的应用程序的RM_UNIQUE_PROCESS结构。

为了满足你的特殊需求,它可能有点过度设计了…… 但如果这是你想要的,那就去拿vs-project吧。