2012-12-26 28 views
16

Tôi cố gắng tìm hiểu ReadDirectoryChangesW chức năng vì vậy tôi có thể được thông báo một cách hiệu quả về việc thay đổi nội dung trong một số thư mục (file bị ghi đè, các file bị xóa, đổi tên, vv ..).C++ WINAPI: ReadDirectoryChangesW() Nhận Notifications đúp

Một trong những quan sát gần đây của tôi là, đối với mỗi tệp hoạt động ghi, tôi luôn nhận được hai thông báo cho một tệp.

Tôi đã theo dõi rất cẩn thận và chắc chắn rằng nếu tôi ghi đè lên một tệp (ví dụ: tệp .txt có nội dung mới - về cơ bản vài chữ cái bên trong), ReadDirectoryChangesW() thông báo cho tôi hai lần cho mỗi tệp đó.

Đây là điều nghiêm trọng, vì tôi dự kiến ​​chỉ được thông báo một lần cho mỗi thay đổi. Tôi không muốn vô tình lặp lại các hoạt động chỉ xảy ra một lần trong đơn của tôi.

Hành vi này có được xác định không? Có cách nào để chỉ nhận được một thông báo cho mỗi một thay đổi không? Có cách nào để có hiệu quả tránh thông báo kép không?

tôi sử dụng:

  • Switch C++
  • Visual Studio 2012
  • Windows 7 x64

tôi sử dụng mã khá cơ bản để làm bài kiểm tra của tôi, nhưng bạn sẽ muốn xem nó ở đây là:

HANDLE hDir = CreateFile(
    lpDir, 
    FILE_LIST_DIRECTORY, 
    FILE_SHARE_WRITE | FILE_SHARE_READ | FILE_SHARE_DELETE, 
    NULL, 
    OPEN_EXISTING, 
    FILE_FLAG_BACKUP_SEMANTICS, 
    NULL); 

    int nCounter = 0; 
    FILE_NOTIFY_INFORMATION strFileNotifyInfo[1024]; 
    DWORD dwBytesReturned = 0; 

    while(TRUE) 
    { 
     if(ReadDirectoryChangesW (hDir, (LPVOID)&strFileNotifyInfo, sizeof(strFileNotifyInfo), FALSE, FILE_NOTIFY_CHANGE_LAST_WRITE, &dwBytesReturned, NULL, NULL) == 0) 
     { 
      ErrorCheck(_T("Reading Directory Change")); 
     } 
     else 
     { 
      _tcout << _T("File Modified: ") << strFileNotifyInfo[0].FileName << endl; 
      _tcout << _T("Loop: ") << nCounter++ << endl; 
     } 
    } 
+0

Trước tiên, bạn nói mọi thao tác ghi, nhưng sau đó ví dụ của bạn sẽ được ghi đè. Tôi sẽ suy đoán rằng ghi đè có thể liên quan đến nhiều hơn một hoạt động từ góc nhìn của thư mục (chẳng hạn như xóa rồi tạo) thay vì chỉ viết/chắp thêm vào một tệp hiện có. Nhưng tôi không có bất kỳ tài liệu tham khảo có thẩm quyền nào về việc này ... – TheUndeadFish

+0

có thể trùng lặp của [Mục nhập tệp hệ thống đồng hồ kép] (http://stackoverflow.com/questions/9902758/filesystemwatcher-double-entries) –

+0

@TheUndeadFish, xin chào và cảm ơn bạn cho ý tưởng của bạn. Nó thực sự rất thông minh. Tôi đã thử các bài kiểm tra của mình với một lá cờ khác. Tôi có thể nói, ví dụ: ** FILE_NOTIFY_CHANGE_ATTRIBUTES ** cũng trả lại hai thông báo. Điều này có thể được giải thích, rằng trên tập tin ghi đè lên, nhiều hơn một thuộc tính thường được thay đổi? –

Trả lời

18

ReadDirectoryChangesW() có một cái nhìn rất thiển cận của hệ thống tập tin. Nó thấy mỗi thay đổi đối với hệ thống tệp và báo cáo nghiêm túc chúng. Và có, thường có nhiều hơn một khi bạn viết vào một tập tin. Nó là một chi tiết thực hiện của hệ thống tập tin cụ thể bạn đang sử dụng, nhưng bất kỳ một trong những phổ biến trong Windows cũng giữ một mục nhập thư mục cho một tập tin lưu trữ siêu dữ liệu cho tập tin.

Vì vậy, bạn sẽ thấy ghi dữ liệu tệp. Nhưng bạn cũng xem nó thay đổi mục nhập thư mục. Đặc biệt là kích thước tệp, có khả năng thay đổi khi bạn viết tệp và thêm dữ liệu vào tệp. Và dấu thời gian cuối cùng ghi và lần truy cập cuối cùng được ghi lại trong mục nhập thư mục. Các api là nếu không mù để các loại thay đổi được thực hiện, nó chỉ thấy viết thấp cấp. Nó cũng hoàn toàn không biết về quy trình cụ thể được yêu cầu cho việc viết.

Đây là điều bạn sẽ phải giải quyết, không có cách nào để phân biệt các ghi này. Tất cả những gì bạn biết là "tập tin đã được thay đổi". Làm thế nào, tại sao, bởi ai và thường xuyên như thế nào là hoàn toàn không thể khám phá.

Một điều khác bạn sẽ phải giải quyết là, tại thời điểm thông báo được tạo, quá trình ghi tệp rất có khả năng vẫn có khóa trên tệp. Điều này ngăn cản bạn làm bất cứ điều gì hữu ích với chính tệp đó. Giống như đọc tập tin hoặc sao chép nó có khả năng thất bại. Bạn phải chờ cho đến khi quá trình được thực hiện với tệp và đã đóng xử lý tệp đó. Không có cách nào để khám phá điều này, ngoài việc cố gắng tự mở tệp và từ chối mọi chia sẻ. Điều này đòi hỏi một bộ đếm thời gian, định kỳ cố gắng để có được một khóa trên tập tin chính mình. Một khi bạn đã nhận được hệ thống ống nước tại chỗ, nhận được nhiều hơn một thông báo thay đổi cho các tập tin không quan trọng nữa.

+2

+1 và cảm ơn bạn đã trả lời. Bạn giải thích rằng theo cách rất tốt đẹp, với ý tưởng được đề xuất cho giải pháp. Tôi sẽ thực hiện giám sát dựa trên bộ đếm thời gian. Câu trả lời của bạn và Sergmat đều rất tốt. Thật khó để quyết định cái nào để đánh dấu là * Câu trả lời được chấp nhận *, nhưng, khi bạn cung cấp thêm thông tin, tôi đang đánh dấu câu trả lời của bạn. Cảm ơn một lần nữa. –

6

Đây là hoạt động kết quả của mã đang chạy đồng thời với nhật ký procmon sau khi tệp lưu trong notepad. Có hai thông báo từ ReadDirectoryChangesW() và hai thông báo từ procmon. 2 IRP_MJ_WRITE 1 từ Notepad (WriteFile) 1 từ hệ thống bộ nhớ cache Manager (CcWriteBehind) procmon

+0

Điều này có vẻ hợp lý nhưng tôi không chắc chắn ... tài liệu cho 'FILE_NOTIFY_CHANGE_LAST_WRITE' tại http://msdn.microsoft.com/en-us/library/windows/desktop/aa365465(v=vs.85).aspx tuyên bố "Mọi thay đổi đối với thời gian ghi cuối cùng của các tệp trong thư mục đã xem hoặc cây con sẽ làm cho hoạt động chờ thông báo thay đổi trở lại. * Hệ điều hành chỉ phát hiện thay đổi cho lần ghi cuối cùng khi tệp được ghi vào đĩa * Đối với các hệ điều hành sử dụng bộ nhớ đệm mở rộng, phát hiện chỉ xảy ra khi bộ nhớ cache bị xóa hoàn toàn. " –

+0

@sergmat: +1 quầng và cảm ơn lời giải thích của bạn. Phân tích của bạn là tuyệt vời và giải thích hoàn hảo vấn đề này. Tôi chỉ xin lỗi, tôi đã không thể tìm thấy câu trả lời của riêng tôi. Có vẻ như, Process Monitor từ Sysinternals.com là một công cụ rất mạnh. –

+0

@NikBougalis, xin chào Nik, vâng, tôi đã đọc đoạn đó từ tài liệu. Có vẻ như Sergmat đã giải thích rằng, và tôi sẽ phải theo dõi tất cả các thông báo dựa trên thời gian trôi qua, vì vậy tôi sẽ tránh những đôi đó. –

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