C++ 使用 ReadDirectoryChangesW 监视文件更改不触发所有操作?
C++ Monitoring filechange with ReadDirectoryChangesW not triggering all Actions?
我有一个应用程序必须监视特定目录中的任何更改。我使用以下代码,但是当我重命名文件时,不会触发 Action FILE_ACTION_RENAMED_NEW_NAME
。实际上,触发 UNDISCOVERED ACTION
get 会导致意外行为?我在这里做错了什么?
char Dir[] = "DIRPATH";
HANDLE hDir = CreateFile(
Dir,
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];
FILE_NOTIFY_INFORMATION *fni = NULL;
while (TRUE)
{
//strFileNotifyInfo = NULL;
DWORD dwBytesReturned = 0;
if (ReadDirectoryChangesW(hDir, (LPVOID)&strFileNotifyInfo, sizeof(strFileNotifyInfo), TRUE, FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_LAST_WRITE, &dwBytesReturned, NULL, NULL) == 0)
{
Exit(GetLastErrorAsString());
}
else
{
char fileName[MAX_PATH] = "";
DWORD offset = 0;
do {
fni = (FILE_NOTIFY_INFORMATION*)(&strFileNotifyInfo[offset]);
int ret = ::WideCharToMultiByte(CP_ACP, 0, fni->FileName, fni->FileNameLength / sizeof(WCHAR), fileName, sizeof(fileName), NULL, NULL);
string Test = Dir;
Test += "\";
Test += fileName;
switch (fni->Action) {
case FILE_ACTION_ADDED:
if (boost::filesystem::is_directory(Test)) {
cout << "Directory added: " << Dir << "\" << fileName << endl;
}
else {
cout << "File added: " << Dir << "\" << fileName << endl;
}
break;
case FILE_ACTION_MODIFIED:
if (boost::filesystem::is_directory(Test)) {
cout << "Directory modified: " << Dir << "\" << fileName << endl;
}
else {
cout << "File modified: " << Dir << "\" << fileName << endl;
}
break;
case FILE_ACTION_REMOVED:
if (boost::filesystem::is_directory(Test)) {
cout << "Directory removed: " << Dir << "\" << fileName << endl;
}
else {
cout << "File removed: " << Dir << "\" << fileName << endl;
}
break;
case FILE_ACTION_RENAMED_NEW_NAME:
if (boost::filesystem::is_directory(Test)) {
cout << "Directory renamend (NEW): " << Dir << "\" << fileName << endl;
}
else {
cout << "File renamed (NEW): " << Dir << "\" << fileName << endl;
}
break;
case FILE_ACTION_RENAMED_OLD_NAME:
if (boost::filesystem::is_directory(Test)) {
cout << "Directory renamed (OLD): " << Dir << "\" << fileName << endl;
}
else {
cout << "File renamed (OLD): " << Dir << "\" << fileName << endl;
}
break;
default:
if (boost::filesystem::is_directory(Test)) {
cout << "Directory UNDISCOVERED ACTION: " << Dir << "\" << fileName << endl;
}
else {
cout << "File UNDISCOVERED ACTION: " << Dir << "\" << fileName << endl;
}
break;
}
::memset(fileName, '[=10=]', sizeof(fileName));
offset += fni->NextEntryOffset;
}
while (fni->NextEntryOffset != 0);
cout << "Loop: " << nCounter++ << endl;
}
}
在名为 MAP
:
的地图中将文件从 file.txt
重命名为 file2.txt
时的一些示例输出
File renamed (OLD): DIRPATH\MAP\file.txt
Directory UNDISCOVERED ACTION: DIRPATH
Loop: 0
Directory modified: DIRPATH\MAP
Loop: 1
FILE_NOTIFY_INFORMATION
不是 fixed-size 结构。它表示一个 fixed-size header 后跟文件名 - 一个可变大小的字符串。
&strFileNotifyInfo[1]
指向 strFileNotifyInfo[0]
之后的文件名中间的某个偏移量。它的值只是 mis-interpreted 充满文件名字符的内存块;本质上是随机垃圾。
相反,您应该使用 FILE_NOTIFY_INFORMATION::NextEntryOffset
在缓冲区中找到 FILE_NOTIFY_INFORMATION
的以下实例。
您的代码将如下所示:
BYTE buffer[4096];
ReadDirectoryChangesW(hDir, buffer, sizeof(buffer), ...);
BYTE* p = buffer;
for (;;) {
FILE_NOTIFY_INFORMATION* info =
reinterpret_cast<FILE_NOTIFY_INFORMATION*>(p);
// Work with `info` as necessary
if (!info->NextEntryOffset) break; // this was last entry
p += info->NextEntryOffset;
}
我有一个应用程序必须监视特定目录中的任何更改。我使用以下代码,但是当我重命名文件时,不会触发 Action FILE_ACTION_RENAMED_NEW_NAME
。实际上,触发 UNDISCOVERED ACTION
get 会导致意外行为?我在这里做错了什么?
char Dir[] = "DIRPATH";
HANDLE hDir = CreateFile(
Dir,
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];
FILE_NOTIFY_INFORMATION *fni = NULL;
while (TRUE)
{
//strFileNotifyInfo = NULL;
DWORD dwBytesReturned = 0;
if (ReadDirectoryChangesW(hDir, (LPVOID)&strFileNotifyInfo, sizeof(strFileNotifyInfo), TRUE, FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_LAST_WRITE, &dwBytesReturned, NULL, NULL) == 0)
{
Exit(GetLastErrorAsString());
}
else
{
char fileName[MAX_PATH] = "";
DWORD offset = 0;
do {
fni = (FILE_NOTIFY_INFORMATION*)(&strFileNotifyInfo[offset]);
int ret = ::WideCharToMultiByte(CP_ACP, 0, fni->FileName, fni->FileNameLength / sizeof(WCHAR), fileName, sizeof(fileName), NULL, NULL);
string Test = Dir;
Test += "\";
Test += fileName;
switch (fni->Action) {
case FILE_ACTION_ADDED:
if (boost::filesystem::is_directory(Test)) {
cout << "Directory added: " << Dir << "\" << fileName << endl;
}
else {
cout << "File added: " << Dir << "\" << fileName << endl;
}
break;
case FILE_ACTION_MODIFIED:
if (boost::filesystem::is_directory(Test)) {
cout << "Directory modified: " << Dir << "\" << fileName << endl;
}
else {
cout << "File modified: " << Dir << "\" << fileName << endl;
}
break;
case FILE_ACTION_REMOVED:
if (boost::filesystem::is_directory(Test)) {
cout << "Directory removed: " << Dir << "\" << fileName << endl;
}
else {
cout << "File removed: " << Dir << "\" << fileName << endl;
}
break;
case FILE_ACTION_RENAMED_NEW_NAME:
if (boost::filesystem::is_directory(Test)) {
cout << "Directory renamend (NEW): " << Dir << "\" << fileName << endl;
}
else {
cout << "File renamed (NEW): " << Dir << "\" << fileName << endl;
}
break;
case FILE_ACTION_RENAMED_OLD_NAME:
if (boost::filesystem::is_directory(Test)) {
cout << "Directory renamed (OLD): " << Dir << "\" << fileName << endl;
}
else {
cout << "File renamed (OLD): " << Dir << "\" << fileName << endl;
}
break;
default:
if (boost::filesystem::is_directory(Test)) {
cout << "Directory UNDISCOVERED ACTION: " << Dir << "\" << fileName << endl;
}
else {
cout << "File UNDISCOVERED ACTION: " << Dir << "\" << fileName << endl;
}
break;
}
::memset(fileName, '[=10=]', sizeof(fileName));
offset += fni->NextEntryOffset;
}
while (fni->NextEntryOffset != 0);
cout << "Loop: " << nCounter++ << endl;
}
}
在名为 MAP
:
file.txt
重命名为 file2.txt
时的一些示例输出
File renamed (OLD): DIRPATH\MAP\file.txt
Directory UNDISCOVERED ACTION: DIRPATH
Loop: 0
Directory modified: DIRPATH\MAP
Loop: 1
FILE_NOTIFY_INFORMATION
不是 fixed-size 结构。它表示一个 fixed-size header 后跟文件名 - 一个可变大小的字符串。
&strFileNotifyInfo[1]
指向 strFileNotifyInfo[0]
之后的文件名中间的某个偏移量。它的值只是 mis-interpreted 充满文件名字符的内存块;本质上是随机垃圾。
相反,您应该使用 FILE_NOTIFY_INFORMATION::NextEntryOffset
在缓冲区中找到 FILE_NOTIFY_INFORMATION
的以下实例。
您的代码将如下所示:
BYTE buffer[4096];
ReadDirectoryChangesW(hDir, buffer, sizeof(buffer), ...);
BYTE* p = buffer;
for (;;) {
FILE_NOTIFY_INFORMATION* info =
reinterpret_cast<FILE_NOTIFY_INFORMATION*>(p);
// Work with `info` as necessary
if (!info->NextEntryOffset) break; // this was last entry
p += info->NextEntryOffset;
}