2010-04-02 9 views
10

当我打开一个文件时,我想知道它是否被另一个进程使用,以便我可以进行特殊处理;任何其他IOException我会冒泡。 IOException的Message属性包含“进程无法访问文件'foo',因为它正在被另一个进程使用”,但这不适合程序化检测。什么是最安全,最稳健的方式来检测另一个进程正在使用的文件?如何判断被捕获的IOException是否由另一个进程使用的文件引起,而不诉诸于解析异常的Message属性

+0

该类型是否真的是IOException还是IOException派生的类型之一? – 2010-04-02 20:01:28

+1

出于兴趣,您为什么需要以编程方式检测?一旦你发现另一个进程正在使用你的文件,你打算做什么? – 2010-04-02 20:02:13

+0

@马克拜尔斯,看到我的评论反对接受的答案。 – 2010-04-02 20:56:29

回答

13

时的出错代码从Win32本地函数返回的IOException这个特殊版本被抛出是ERROR_SHARING_VIOLATIONDocumentation)。它具有0x20数值,但实际存储为0x80070020上异常的HRESULT特性(它的结果的通话MakeHRFromErrorCode)。

所以检查共享冲突正在检查在IOExceptionHResult属性值0x80070020的程序化的方式。

public static bool IsSharingViolation(this IOException ex) { 
    return 0x80070020 == Marshal.GetHRForException(ex); 
} 

但是我的确质疑你在这种情况下想要做什么,因为它是由于共享冲突而抛出的。一旦抛出异常,其他进程可能会退出,从而消除违规。

+1

为什么不直接使用'ex.HResult'而不是'Marshal.GetHRForException'? – 2010-04-02 20:16:55

+2

@Anders,因为HResult属性具有受保护的可访问级别,因此通常不可访问。 – JaredPar 2010-04-02 20:18:42

+1

梦幻般的答案JaredPar,谢谢...在回答你的问题;我需要检测这种情况,因为我需要一个表达层的友好信息 - 没关系,如果由于我的应用程序的性质,冲突可能暂时不存在......再次感谢 – 2010-04-02 20:49:43

1

我没有足够的“代表”,所以希望这个“答案”就行了评论...

接受的答案正是我一直在寻找和完美的作品,但这里的乡亲和类似有问题质疑检查文件是否被锁定的效用。测试一个文件是否被锁定的效用函数没有多大用处是正确的,因为在接下来的语句中状态可能已经改变。

但是,尝试锁定操作然后以不同方式响应以锁定错误与一般错误的模式是有效且有用的。最明显的做法是等待一点点,然后重试操作。这可以概括为一个辅助功能是这样的:

protected static void RetryLock(Action work) { 
    // Retry LOCK_MAX_RETRIES times if file is locked by another process 
    for (int i = 1; i <= LOCK_MAX_RETRIES; i++) { 
     try { 
      work(); 
      return; 
     } catch (IOException ex) { 
      if (i == LOCK_MAX_RETRIES || (uint) ex.HResult != 0x80070020) { 
       throw; 
      } else { 
       // Min should be long enough to generally allow other process to finish 
       // while max should be short enough such that RETRIES * MAX isn't intolerable 
       Misc.SleepRandom(LOCK_MIN_SLEEP_MS, LOCK_MAX_SLEEP_MS); 
      } 
     } 
    } 
} // RetryLock 

...然后可以使用这样的:

public string DoSomething() { 
    string strReturn = null; 
    string strPath = @"C:\Some\File\Path.txt"; 
    // Do some initial work... 

    //---------------------------------------------------------------------------------------------------- 
    // NESTED FUNCTION to do main logic, RetryLock will retry up to N times on lock failures 
    Action doWork = delegate { 
     using (FileStream objFile = File.Open(strPath, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None)) { 
      // Does work here if lock succeeded, else File.Open will throw ex 
      strReturn = new StreamReader(objFile).ReadLine(); 
     } 
    }; // delegate doWork 
    //---------------------------------------------------------------------------------------------------- 

    RetryLock(doWork); // Throws original ex if non-locking related or tried max times 
    return strReturn; 
} 

...无论如何,以防万一有人有类似需求的认定发布该模式很有用。

+1

如果你使用C#6,这是使用过滤器异常的完美情况'catch(IOException ex)when(i 2015-11-04 20:35:39

相关问题