C++ WinApi:ReadDirectoryChangesW()接收双重通知

Bun*_*ori 18 c++ windows file-io winapi visual-c++

我尝试了解ReadDirectoryChangesW功能,以便能够有效地了解多个目录中的内容更改(文件被覆盖,文件被删除,重命名等等).

我最近的一个观察是,对于每个文件写入操作,我总是收到两个单个文件的通知.

我非常仔细地追踪了这一点,我确信,如果我覆盖一个文件(比如一个带有新内容的.txt文件 - 里面几个额外的字母),ReadDirectoryChangesW()每个文件保存会通知我两次.

这是严肃的事情,因为我希望每次更改只通知一次.我不希望无意中重复在我的应用程序中只发生一次的操作.

这种行为是否已知?有没有办法每次更改只收到一个通知,好吗?有没有办法有效避免双重通知?

我用:

  • 非托管C++
  • Visual Studio 2012
  • Windows 7 x64

我使用非常基本的代码来进行测试,但你会想看到它,所以这里是:

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;
        }
    }
Run Code Online (Sandbox Code Playgroud)

Han*_*ant 25

ReadDirectoryChangesW()有一个非常近视的文件系统.它会查看文件系统的每个更改并尽职地报告它们.是的,当你写一个文件时,往往不止一个.它是您正在使用的特定文件系统的实现细节,但Windows中的任何常见文件系统也会保存用于存储文件元数据的文件的目录条目.

所以你看到了文件数据的写入.但是你看到它改变了目录条目.特别是文件大小,当您编写文件并将数据添加到文件时可能会更改.以及目录条目中记录的最后写入和最后访问时间戳.api对于所做的更改是盲目的,它只看到低级别的写入.它也完全没有意识到要求写入的特定进程.

这是你必须要处理的事情,没有办法区分这些写法.你所知道的只是"文件被更改了".如何,为什么,由谁以及经常是完全无法发现的.

您需要处理的其他事情是,在生成通知时,写入文件的进程很可能仍然锁定文件.这会阻止您自己对文件做任何有用的事情.像阅读文件或复制它可能会失败.您必须等到该文件完成该过程并关闭其文件句柄.除了尝试自己打开文件并拒绝任何共享之外,没有办法发现这一点.这需要一个计时器,定期尝试自己锁定文件.一旦你掌握了管道,获得该文件的多个更改通知就不再重要了.

  • +1并感谢您的回答.您以非常好的方式解释了提出的解决方案的想法.我将实现基于计时器的监控.你的和Sergmat的答案都非常好.很难确定哪一个标记为*Accepted Answer*,但是,当您提供其他信息时,我正在标记您的答案.再次感谢. (2认同)

ser*_*mat 8

这是在记事本中保存文件后,与procmon记录同时运行代码的结果操作.ReadDirectoryChangesW()有两个通知,procmon有两个通知.2来自系统缓存管理器(CcWriteBehind)的记事本(WriteFile)1中的IRP_MJ_WRITE 1 将procmon