Я пытаюсь использовать ReadDirectoryChangesW
отслеживать, когда файл создается, копируется или перемещается в контролируемый каталог.
Моя проблема в том, что когда я копирую или создаю файл в контролируемом каталоге, событие FILE_ACTION_ADDED не регистрируется ReadDirectoryChangesW
вместо этого фиксируются только события FILE_ACTION_MODIFIED.
С другой стороны, когда я перемещаю файл (вместо копирования или создания) из другого каталога в отслеживаемый каталог, создается файл FILE_ACTION_ADDED.
Мне было интересно, если кто-нибудь знает способ заставить ReadDirectoryChangesW захватывать FILE_ACTION_ADDED в 3 моих случаях: создавать, копировать и перемещать.
Я звоню 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
с разными флагами для каждого случая?
по факту ReadDirectoryChangesW
возвращает буфер, который может содержать более одного FILE_NOTIFY_INFORMATION
состав. Первый, как и ожидалось, в начале буфера, но если поле NextEntryOffset
не является нулевым, это смещение (в буфере символов) для следующей структуры.
Итак, ваш обратный вызов должен быть:
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);
}
Других решений пока нет …