10

ファイルを開くときに、別のプロセスで使用されているかどうかを知りたいので、特別な処理を実行できます。その他の IOException はバブルアップします。IOException の Message プロパティには、「別のプロセスによって使用されているため、プロセスはファイル 'foo' にアクセスできません。」が含まれていますが、これはプログラムによる検出には適していません。別のプロセスで使用されているファイルを検出する最も安全で堅牢な方法は何ですか?

4

2 に答える 2

16

この特定のバージョンのIOExceptionは、Win32 ネイティブ関数から返されたエラー コードがERROR_SHARING_VIOLATION(ドキュメント)の場合にスローされます。の数値を持ちますが、0x20実際には例外0x80070020HRESULTプロパティとして格納されます (これは MakeHRFromErrorCode を呼び出した結果です)。

したがって、共有違反をチェックするプログラムによる方法は、値のHResultプロパティをチェックすることです。 IOException0x80070020

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

ただし、共有違反の結果としてスローされたというシナリオで、正確に何をしたいのか疑問に思います. 例外がスローされた瞬間に、他のプロセスが終了し、違反が解消される可能性があります。

于 2010-04-02T20:09:32.790 に答える
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;
}

...とにかく、同様のニーズを持つ誰かがパターンが役立つと思う場合に備えて投稿してください.

于 2015-11-04T20:25:55.260 に答える