复制或创建文件时,ReadDirectoryChangesW不捕获FILE_ACTION_ADDED

时间:2017-03-30 15:25:26

标签: c++ c windows file-monitoring

我尝试使用ReadDirectoryChangesW来跟踪文件创建,复制或移动到受监控目录的时间。

我的问题是,当我在受监控目录上复制或创建文件时,ReadDirectoryChangesW没有捕获FILE_ACTION_ADDED事件,而是仅捕获FILE_ACTION_MODIFIED事件。

另一方面,当我将文件(而不是复制或创建)从另一个目录移动到受监控目录时,会捕获一个FILE_ACTION_ADDED。

我想知道是否有人知道如何让ReadDirectoryChangesW在我的3个案例中捕获FILE_ACTION_ADDED:创建,复制和移动。

我这样打电话给ReadDirectoryChangesW

ReadDirectoryChangesW(directory_handle, buffer, MAX_EVENTs_BUFFER,
    FALSE, FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME |
    FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE,
    NULL, (LPOVERLAPPED)usr_data, FileIOCompletionRoutine)

我使用CreateFileA初始化directory_handle

CreateFileA(directory_path.c_str(), 
    FILE_LIST_DIRECTORY, FILE_SHARE_READ | FILE_SHARE_WRITE |
    FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | 
    FILE_FLAG_OVERLAPPED, NULL);

然后,在我的FileIOCompletionRoutine上,当我将文件复制到受监控目录时,或者当我创建文件时,我只会在移动文件时从未收到FILE_ACTION_ADDED。这是正常行为还是我做错了什么?

编辑1:

VOID CALLBACK FileIOCompletionRoutine(_In_ DWORD err, _In_ DWORD bytes, _Inout_ LPOVERLAPPED lpOverlapped)
{
    CUSTOM_OVERLAPPED* pCustomOverlapped = (CUSTOM_OVERLAPPED*)lpOverlapped;
    char* buffer_offset = (char*)pCustomOverlapped->buffer;
    PFILE_NOTIFY_INFORMATION pInfo = (PFILE_NOTIFY_INFORMATION)buffer_offset;

    do
    {        
        pInfo = (PFILE_NOTIFY_INFORMATION)buffer_offset;
        switch (pInfo->Action)
        {
            case FILE_ACTION_ADDED:
            {              
                std::cout << "file added!\n";
                break;
            }
            case FILE_ACTION_MODIFIED:
            {
                std::cout << "file modified!\n";
                break;
            }
            // and so on...
        }
        buffer_offset += pInfo->NextEntryOffset;        
    } while(pInfo->NextEntryOffset);
}

编辑2:

我发现,如果我从FILE_NOTIFY_CHANGE_LAST_WRITE中移除ReadDirectoryChangesW,则在创建新文件时以及当我执行剪切和粘贴时正确捕获FILE_ACTION_ADDED事件,但不是我会复制并粘贴,在这种情况下它会触发FILE_ACTION_MODIFIED。为了在复制并粘贴到受监控目录时获得FILE_ACTION_ADDED,我还需要删除FILE_NOTIFY_CHANGE_SIZE标记。

因此,如果想要在受监视目录中跟踪新文件(创建,复制或移动),我只需要FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME函数上的标记ReadDirectoryChangesW。 如果我想跟踪已修改的(已存在于目录中)文件,我需要FILE_NOTIFY_CHANGE_SIZE,但我不能使用ReadDirectoryChangesW中的三个标记来跟踪新文件和修改过的文件。

您是否有人找到了使用逻辑或三个标志跟踪所有这些事件的方法,还是我必须为每个案例调用ReadDirectoryChangesW不同的标志?

1 个答案:

答案 0 :(得分:1)

实际上ReadDirectoryChangesW返回一个可以包含多个FILE_NOTIFY_INFORMATION结构的缓冲区。第一个在缓冲区的开头是预期的,但如果字段NextEntryOffset不为null,则它是下一个结构的偏移量(在char缓冲区中)。

所以你的回调应该是:

VOID CALLBACK FileIOCompletionRoutine(_In_ DWORD err, _In_ DWORD bytes, _Inout_ LPOVERLAPPED lpOverlapped)
{
    CUSTOM_OVERLAPPED* pCustomOverlapped = (CUSTOM_OVERLAPPED*)lpOverlapped;
    char* buffer_offset = (char*)pCustomOverlapped->buffer;
    PFILE_NOTIFY_INFORMATION pInfo = (PFILE_NOTIFY_INFORMATION)buffer_offset;

    do {
        switch (pInfo->Action)
        {
            case FILE_ACTION_ADDED:
            {              
                std::cout << "file added!\n";
                break;
            }
            case FILE_ACTION_MODIFIED:
            {
                std::cout << "file modified!\n";
                break;
            }
            // and so on...
        }
        pInfo = (PFILE_NOTIFY_INFORMATION)(buffer_offset + pInfo->NextEntryOffset);
    } while (0 != pInfo->NextEntryOffset);
}