2010-04-02 13 views
10

Khi tôi mở một tệp, tôi muốn biết liệu nó có đang được sử dụng bởi một quy trình khác không. thực hiện xử lý đặc biệt; bất kỳ IOException khác tôi sẽ bong bóng lên. Thuộc tính Message của IOException chứa "Quá trình không thể truy cập tệp 'foo' vì nó đang được sử dụng bởi một tiến trình khác.", Nhưng điều này không phù hợp cho việc phát hiện có lập trình. Cách an toàn nhất, mạnh mẽ nhất để phát hiện tệp đang được sử dụng bởi quy trình khác là gì?Làm thế nào để biết nếu một IOException bị bắt gặp là do tệp đang được sử dụng bởi một tiến trình khác, mà không cần phải phân tích cú pháp thuộc tính Message của

+0

Loại thực sự là một IOException hay là một trong các kiểu bắt nguồn từ IOException? –

+1

Không quan tâm, tại sao bạn cần phát hiện điều này theo chương trình? Bạn dự định làm gì khi bạn đã phát hiện ra rằng một quy trình khác đang sử dụng tệp của bạn? –

+0

@Mark Byers, xem nhận xét của tôi về câu trả lời được chấp nhận. –

Trả lời

13

Đây là phiên bản đặc biệt của IOException được ném khi mã lỗi trả về từ hàm Win32 là ERROR_SHARING_VIOLATION (Documentation). Nó có giá trị số của 0x20 nhưng thực sự được lưu trữ như 0x80070020 trên HRESULT tài sản của ngoại lệ (đó là kết quả gọi MakeHRFromErrorCode).

vì vậy, cách programatic kiểm tra vì vi phạm chia sẻ được kiểm tra HResult tài sản trên IOException cho giá trị 0x80070020.

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

Tuy nhiên, tôi đặt câu hỏi chính xác bạn muốn làm gì trong trường hợp nó được đưa ra do vi phạm chia sẻ. Thời điểm ngoại lệ được ném vào quá trình khác có thể thoát ra và do đó loại bỏ vi phạm.

+1

Tại sao không sử dụng 'ex.HResult' trực tiếp thay vì' Marshal.GetHRForException'? –

+2

@Anders vì tài sản HResult có mức độ truy cập được bảo vệ nên thường không thể truy cập được. – JaredPar

+1

Câu trả lời tuyệt vời JaredPar, cảm ơn ... Để trả lời câu hỏi của bạn; Tôi cần phải phát hiện kịch bản này vì tôi cần một thông điệp thân thiện cho lớp trình bày - sẽ ổn nếu xung đột có thể không tồn tại ngay sau đó, do bản chất của ứng dụng của tôi ... cảm ơn một lần nữa –

1

tôi không có đủ "đại diện" để bình luận vì vậy hy vọng "câu trả lời" đây là OK ...

Câu trả lời được chấp nhận là chính xác những gì tôi đang tìm kiếm và hoạt động hoàn hảo, nhưng người ở đây và trên tương tự câu hỏi đã đặt câu hỏi về tiện ích kiểm tra xem tệp có bị khóa hay không. Đúng là một hàm tiện ích để kiểm tra xem một tệp có bị khóa không được sử dụng nhiều hay không bởi vì trên báo cáo tiếp theo, trạng thái có thể đã thay đổi.

Nhưng mẫu thử hoạt động khóa và sau đó phản hồi khác nhau để khóa lỗi so với lỗi chung là hợp lệ và hữu ích. Điều rõ ràng nhất cần làm là chờ một chút và thử lại thao tác. Điều này có thể được khái quát hóa thành một hàm helper như thế này:

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 

... mà sau đó có thể được sử dụng như thế này:

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; 
} 

... dù sao, chỉ cần gửi bài trong trường hợp ai đó có nhu cầu tương tự như tìm thấy mô hình hữu ích.

+1

Nếu bạn đang sử dụng C# 6 đây là tình huống hoàn hảo để sử dụng các ngoại lệ được lọc 'catch (IOException ex) khi (i

Các vấn đề liên quan