0

我试图用来ReadDirectoryChangesW跟踪文件何时被创建、复制或移动到受监视的目录。

我的问题是,当我在受监视目录上复制或创建文件时,没有捕获ReadDirectoryChangesWFILE_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为每种情况调用不同的标志?

4

1 回答 1

1

实际上ReadDirectoryChangesW返回一个可以包含多个FILE_NOTIFY_INFORMATION结构的缓冲区。第一个在缓冲区的开头与预期的一样,但如果该字段NextEntryOffset不为空,则它是下一个结构的偏移量(在 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);
}
于 2017-03-30T17:50:23.083 回答