哈喽,各位好!今天咱们来聊聊C++里文件系统事件监控这事儿,听起来高大上,其实也没那么神秘。咱们主要讲两种方法:inotify
(Linux)和 ReadDirectoryChangesW
(Windows)。这俩货都是为了让你写的程序能像个好奇宝宝一样,时刻盯着文件系统的动静,一有风吹草动就立马知道。
为什么要监控文件系统?
你可能会问,好端端的,为啥要盯着文件系统?理由可多了:
- 实时同步: 比如网盘,文件一改动,立马同步到云端。
- 构建系统: 像
make
这种工具,需要知道哪些源文件变动了,才能重新编译。 - 安全监控: 监测恶意软件是否在偷偷修改系统文件。
- 日志分析: 实时监控日志文件,发现异常情况立即报警。
- 缓存失效: 缓存系统需要知道底层文件是否被修改,及时更新缓存。
总之,只要你的程序需要对文件系统的变化做出反应,那文件系统事件监控就是个必备技能。
Linux 下的 inotify
inotify
是 Linux 内核提供的一个文件系统事件通知接口。它允许你监控文件或目录,当文件或目录发生变化时,内核会通知你的程序。
inotify
的基本概念:
- inotify 实例: 就像一个监视器,你需要先创建一个
inotify
实例才能开始监控。 - watch 描述符 (wd): 每个被监控的文件或目录都有一个唯一的 watch 描述符,你可以通过它来标识监控对象。
- 事件掩码: 指定你感兴趣的事件类型,比如文件被创建、删除、修改等等。
inotify
的使用步骤:
-
创建
inotify
实例: 使用inotify_init()
函数创建。#include <iostream> #include <sys/inotify.h> #include <unistd.h> // close() #include <cstring> // memset #include <cerrno> // errno int main() { int fd = inotify_init(); if (fd == -1) { std::cerr << "inotify_init failed: " << strerror(errno) << std::endl; return 1; } std::cout << "inotify instance created successfully." << std::endl; // ... 后面添加监控和处理事件的代码 close(fd); // 记得关闭 return 0; }
-
添加 watch: 使用
inotify_add_watch()
函数添加要监控的文件或目录。#include <iostream> #include <sys/inotify.h> #include <unistd.h> // close() #include <cstring> // memset #include <cerrno> // errno int main() { int fd = inotify_init(); if (fd == -1) { std::cerr << "inotify_init failed: " << strerror(errno) << std::endl; return 1; } std::cout << "inotify instance created successfully." << std::endl; const char *path = "/tmp/watched_directory"; // 你要监控的目录 int wd = inotify_add_watch(fd, path, IN_MODIFY | IN_CREATE | IN_DELETE); if (wd == -1) { std::cerr << "inotify_add_watch failed: " << strerror(errno) << std::endl; close(fd); return 1; } std::cout << "Watching " << path << " (wd = " << wd << ")" << std::endl; // ... 后面添加读取和处理事件的代码 close(fd); return 0; }
这里的
IN_MODIFY | IN_CREATE | IN_DELETE
是事件掩码,表示我们对文件修改、创建和删除事件感兴趣。 常用的事件掩码如下表:事件掩码 含义 IN_ACCESS
文件被访问 IN_MODIFY
文件被修改 IN_ATTRIB
文件属性被修改 IN_CLOSE_WRITE
文件被关闭(以可写方式打开) IN_CLOSE_NOWRITE
文件被关闭(以只读方式打开) IN_OPEN
文件被打开 IN_CREATE
文件/目录被创建 IN_DELETE
文件/目录被删除 IN_DELETE_SELF
监控的文件/目录自身被删除 IN_MOVE_SELF
监控的文件/目录自身被移动 IN_MOVE_FROM
文件从监控目录移出 IN_MOVE_TO
文件移入监控目录 IN_ALL_EVENTS
所有事件 IN_ONLYDIR
只监控目录 IN_DONT_FOLLOW
不跟踪符号链接 IN_MASK_ADD
将事件添加到现有的掩码中,而不是替换 IN_ONESHOT
只监控一次事件,然后自动移除 watch -
读取事件: 使用
read()
函数从inotify
实例的文件描述符中读取事件。#include <iostream> #include <sys/inotify.h> #include <unistd.h> // close(), read() #include <cstring> // memset #include <cerrno> // errno #include <limits.h> // PATH_MAX int main() { int fd = inotify_init(); if (fd == -1) { std::cerr << "inotify_init failed: " << strerror(errno) << std::endl; return 1; } std::cout << "inotify instance created successfully." << std::endl; const char *path = "/tmp/watched_directory"; // 你要监控的目录 int wd = inotify_add_watch(fd, path, IN_MODIFY | IN_CREATE | IN_DELETE); if (wd == -1) { std::cerr << "inotify_add_watch failed: " << strerror(errno) << std::endl; close(fd); return 1; } std::cout << "Watching " << path << " (wd = " << wd << ")" << std::endl; char buffer[4096]; // 用于读取事件的缓冲区 while (true) { ssize_t len = read(fd, buffer, sizeof(buffer)); if (len == -1) { std::cerr << "read failed: " << strerror(errno) << std::endl; break; } // 处理读取到的事件 char *ptr = buffer; while (ptr < buffer + len) { struct inotify_event *event = (struct inotify_event *)ptr; if (event->mask & IN_CREATE) { if (event->mask & IN_ISDIR) { std::cout << "Directory created: " << event->name << std::endl; } else { std::cout << "File created: " << event->name << std::endl; } } if (event->mask & IN_DELETE) { if (event->mask & IN_ISDIR) { std::cout << "Directory deleted: " << event->name << std::endl; } else { std::cout << "File deleted: " << event->name << std::endl; } } if (event->mask & IN_MODIFY) { std::cout << "File modified: " << event->name << std::endl; } ptr += sizeof(struct inotify_event) + event->len; } } close(fd); return 0; }
这段代码会一直循环读取事件,直到发生错误。 注意,
read()
函数是阻塞的,也就是说,如果没有事件发生,它会一直等待。 -
处理事件: 读取到的事件信息都保存在
inotify_event
结构体中。struct inotify_event { int wd; /* Watch descriptor */ uint32_t mask; /* Mask of events */ uint32_t cookie; /* Cookie to synchronize two events */ uint32_t len; /* Length of name field */ char name[]; /* Optional null-terminated name */ };
wd
:发生事件的 watch 描述符。mask
:发生的事件类型。name
:发生事件的文件或目录名(如果事件与文件或目录关联)。
-
移除 watch: 使用
inotify_rm_watch()
函数移除不再需要监控的文件或目录。inotify_rm_watch(fd, wd);
-
关闭
inotify
实例: 使用close()
函数关闭inotify
实例。close(fd);
完整示例:
#include <iostream>
#include <sys/inotify.h>
#include <unistd.h>
#include <cstring>
#include <cerrno>
#include <limits.h>
int main() {
int fd = inotify_init();
if (fd == -1) {
std::cerr << "inotify_init failed: " << strerror(errno) << std::endl;
return 1;
}
const char *path = "/tmp/watched_directory";
int wd = inotify_add_watch(fd, path, IN_MODIFY | IN_CREATE | IN_DELETE | IN_MOVE);
if (wd == -1) {
std::cerr << "inotify_add_watch failed: " << strerror(errno) << std::endl;
close(fd);
return 1;
}
char buffer[4096];
while (true) {
ssize_t len = read(fd, buffer, sizeof(buffer));
if (len == -1) {
std::cerr << "read failed: " << strerror(errno) << std::endl;
break;
}
char *ptr = buffer;
while (ptr < buffer + len) {
struct inotify_event *event = (struct inotify_event *)ptr;
if (event->mask & IN_CREATE) {
if (event->mask & IN_ISDIR) {
std::cout << "Directory created: " << event->name << std::endl;
} else {
std::cout << "File created: " << event->name << std::endl;
}
}
if (event->mask & IN_DELETE) {
if (event->mask & IN_ISDIR) {
std::cout << "Directory deleted: " << event->name << std::endl;
} else {
std::cout << "File deleted: " << event->name << std::endl;
}
}
if (event->mask & IN_MODIFY) {
std::cout << "File modified: " << event->name << std::endl;
}
if (event->mask & IN_MOVE_SELF) {
std::cout << "Watched directory was moved or renamed." << std::endl;
break; // 需要重新设置watch,因为wd可能已经失效
}
if (event->mask & IN_MOVED_FROM) {
std::cout << "File/directory moved out: " << event->name << std::endl;
}
if (event->mask & IN_MOVED_TO) {
std::cout << "File/directory moved in: " << event->name << std::endl;
}
ptr += sizeof(struct inotify_event) + event->len;
}
}
inotify_rm_watch(fd, wd);
close(fd);
return 0;
}
编译和运行:
- 创建一个目录
/tmp/watched_directory
。 - 将代码保存为
inotify_example.cpp
。 - 使用以下命令编译:
g++ inotify_example.cpp -o inotify_example
- 运行程序:
./inotify_example
然后,你可以尝试在 /tmp/watched_directory
目录下创建、删除或修改文件,看看程序是否能正确地检测到这些事件。
inotify
的限制:
- 最大 watch 数量:
inotify
实例可以监控的最大文件和目录数量是有限制的,可以通过/proc/sys/fs/inotify/max_user_watches
文件查看和修改。 如果watch数量超过限制,inotify_add_watch
会返回ENOSPC错误。 - 事件丢失: 如果事件发生得太快,或者程序处理事件的速度不够快,可能会导致事件丢失。
- 递归监控:
inotify
本身不支持递归监控目录,你需要自己实现递归遍历目录并添加 watch。不过,有些库(比如 Boost.Filesystem)可以简化这个过程。
Windows 下的 ReadDirectoryChangesW
在 Windows 系统上,我们可以使用 ReadDirectoryChangesW
函数来监控目录的变化。 这个函数的功能和 inotify
类似,但使用方式略有不同。
ReadDirectoryChangesW
的基本概念:
- 目录句柄: 你需要先打开一个目录的句柄才能开始监控。
- 缓冲区:
ReadDirectoryChangesW
函数会将事件信息写入一个缓冲区,你需要自己解析这个缓冲区。 - Overlapped I/O:
ReadDirectoryChangesW
函数可以使用 Overlapped I/O 模式,实现异步监控。
ReadDirectoryChangesW
的使用步骤:
-
打开目录句柄: 使用
CreateFileW
函数打开要监控的目录。#include <iostream> #include <windows.h> int main() { LPCWSTR directoryPath = L"\\?\C:\watched_directory"; // 你要监控的目录,注意使用宽字符 HANDLE hDirectory = CreateFileW( directoryPath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED, // 需要FILE_FLAG_BACKUP_SEMANTICS才能打开目录 NULL ); if (hDirectory == INVALID_HANDLE_VALUE) { std::cerr << "CreateFileW failed: " << GetLastError() << std::endl; return 1; } std::cout << "Directory handle created successfully." << std::endl; // ... 后面添加监控和处理事件的代码 CloseHandle(hDirectory); // 记得关闭句柄 return 0; }
注意:
CreateFileW
函数需要使用宽字符(LPCWSTR
)。- 打开目录时需要指定
FILE_FLAG_BACKUP_SEMANTICS
标志。 - 为了实现异步监控,需要指定
FILE_FLAG_OVERLAPPED
标志。 - UNC 路径需要添加
\\?\
前缀才能正常工作,例如\\?\C:\watched_directory
。
-
调用
ReadDirectoryChangesW
: 使用ReadDirectoryChangesW
函数开始监控目录。#include <iostream> #include <windows.h> #include <vector> int main() { LPCWSTR directoryPath = L"\\?\C:\watched_directory"; // 你要监控的目录,注意使用宽字符 HANDLE hDirectory = CreateFileW( directoryPath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED, // 需要FILE_FLAG_BACKUP_SEMANTICS才能打开目录 NULL ); if (hDirectory == INVALID_HANDLE_VALUE) { std::cerr << "CreateFileW failed: " << GetLastError() << std::endl; return 1; } std::cout << "Directory handle created successfully." << std::endl; DWORD bufferSize = 4096; std::vector<BYTE> buffer(bufferSize); DWORD bytesReturned; OVERLAPPED overlapped; memset(&overlapped, 0, sizeof(overlapped)); overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); // 创建事件对象 if (overlapped.hEvent == NULL) { std::cerr << "CreateEvent failed: " << GetLastError() << std::endl; CloseHandle(hDirectory); return 1; } BOOL success = ReadDirectoryChangesW( hDirectory, buffer.data(), bufferSize, TRUE, // 是否监控子目录 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_LAST_ACCESS | FILE_NOTIFY_CHANGE_CREATION | FILE_NOTIFY_CHANGE_SECURITY, &bytesReturned, &overlapped, NULL ); if (!success) { std::cerr << "ReadDirectoryChangesW failed: " << GetLastError() << std::endl; CloseHandle(hDirectory); CloseHandle(overlapped.hEvent); return 1; } std::cout << "Monitoring directory changes..." << std::endl; // ... 后面添加等待和处理事件的代码 CloseHandle(hDirectory); CloseHandle(overlapped.hEvent); return 0; }
-
FILE_NOTIFY_CHANGE_FILE_NAME
等是事件掩码,表示我们对文件名称、目录名称、属性等变化感兴趣。 常用的事件掩码如下表:事件掩码 含义 FILE_NOTIFY_CHANGE_FILE_NAME
文件名发生变化 FILE_NOTIFY_CHANGE_DIR_NAME
目录名发生变化 FILE_NOTIFY_CHANGE_ATTRIBUTES
文件属性发生变化 FILE_NOTIFY_CHANGE_SIZE
文件大小发生变化 FILE_NOTIFY_CHANGE_LAST_WRITE
文件最后写入时间发生变化 FILE_NOTIFY_CHANGE_LAST_ACCESS
文件最后访问时间发生变化 FILE_NOTIFY_CHANGE_CREATION
文件创建时间发生变化 FILE_NOTIFY_CHANGE_SECURITY
文件的安全描述符 (ACL) 发生变化 -
TRUE
表示递归监控子目录,FALSE
表示只监控当前目录。
-
-
等待事件: 由于我们使用了 Overlapped I/O,
ReadDirectoryChangesW
函数会立即返回,我们需要使用GetOverlappedResult
或者WaitForSingleObject
函数来等待事件发生。#include <iostream> #include <windows.h> #include <vector> int main() { LPCWSTR directoryPath = L"\\?\C:\watched_directory"; // 你要监控的目录,注意使用宽字符 HANDLE hDirectory = CreateFileW( directoryPath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED, // 需要FILE_FLAG_BACKUP_SEMANTICS才能打开目录 NULL ); if (hDirectory == INVALID_HANDLE_VALUE) { std::cerr << "CreateFileW failed: " << GetLastError() << std::endl; return 1; } std::cout << "Directory handle created successfully." << std::endl; DWORD bufferSize = 4096; std::vector<BYTE> buffer(bufferSize); DWORD bytesReturned; OVERLAPPED overlapped; memset(&overlapped, 0, sizeof(overlapped)); overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); // 创建事件对象 if (overlapped.hEvent == NULL) { std::cerr << "CreateEvent failed: " << GetLastError() << std::endl; CloseHandle(hDirectory); return 1; } BOOL success = ReadDirectoryChangesW( hDirectory, buffer.data(), bufferSize, TRUE, // 是否监控子目录 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_LAST_ACCESS | FILE_NOTIFY_CHANGE_CREATION | FILE_NOTIFY_CHANGE_SECURITY, &bytesReturned, &overlapped, NULL ); if (!success) { std::cerr << "ReadDirectoryChangesW failed: " << GetLastError() << std::endl; CloseHandle(hDirectory); CloseHandle(overlapped.hEvent); return 1; } std::cout << "Monitoring directory changes..." << std::endl; while (true) { DWORD waitResult = WaitForSingleObject(overlapped.hEvent, INFINITE); // 等待事件发生 if (waitResult == WAIT_OBJECT_0) { GetOverlappedResult(hDirectory, &overlapped, &bytesReturned, FALSE); // 获取结果 // 处理事件 (稍后添加) // 重新调用 ReadDirectoryChangesW 准备下一次监控 success = ReadDirectoryChangesW( hDirectory, buffer.data(), bufferSize, TRUE, FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_LAST_ACCESS | FILE_NOTIFY_CHANGE_CREATION | FILE_NOTIFY_CHANGE_SECURITY, &bytesReturned, &overlapped, NULL ); if (!success) { std::cerr << "ReadDirectoryChangesW failed: " << GetLastError() << std::endl; break; } } else { std::cerr << "WaitForSingleObject failed: " << GetLastError() << std::endl; break; } } CloseHandle(hDirectory); CloseHandle(overlapped.hEvent); return 0; }
这里我们使用
WaitForSingleObject
函数来等待overlapped.hEvent
事件发生。INFINITE
表示无限等待。 -
处理事件: 当事件发生时,我们需要解析缓冲区中的事件信息。
#include <iostream> #include <windows.h> #include <vector> #include <string> #include <locale> #include <codecvt> // 辅助函数:将宽字符串转换为窄字符串 std::string WStringToString(const std::wstring& wstr) { std::wstring_convert<std::codecvt_utf8<wchar_t>> converter; return converter.to_bytes(wstr); } int main() { LPCWSTR directoryPath = L"\\?\C:\watched_directory"; // 你要监控的目录,注意使用宽字符 HANDLE hDirectory = CreateFileW( directoryPath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED, // 需要FILE_FLAG_BACKUP_SEMANTICS才能打开目录 NULL ); if (hDirectory == INVALID_HANDLE_VALUE) { std::cerr << "CreateFileW failed: " << GetLastError() << std::endl; return 1; } std::cout << "Directory handle created successfully." << std::endl; DWORD bufferSize = 4096; std::vector<BYTE> buffer(bufferSize); DWORD bytesReturned; OVERLAPPED overlapped; memset(&overlapped, 0, sizeof(overlapped)); overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); // 创建事件对象 if (overlapped.hEvent == NULL) { std::cerr << "CreateEvent failed: " << GetLastError() << std::endl; CloseHandle(hDirectory); return 1; } BOOL success = ReadDirectoryChangesW( hDirectory, buffer.data(), bufferSize, TRUE, // 是否监控子目录 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_LAST_ACCESS | FILE_NOTIFY_CHANGE_CREATION | FILE_NOTIFY_CHANGE_SECURITY, &bytesReturned, &overlapped, NULL ); if (!success) { std::cerr << "ReadDirectoryChangesW failed: " << GetLastError() << std::endl; CloseHandle(hDirectory); CloseHandle(overlapped.hEvent); return 1; } std::cout << "Monitoring directory changes..." << std::endl; while (true) { DWORD waitResult = WaitForSingleObject(overlapped.hEvent, INFINITE); // 等待事件发生 if (waitResult == WAIT_OBJECT_0) { GetOverlappedResult(hDirectory, &overlapped, &bytesReturned, FALSE); // 获取结果 // 处理事件 DWORD offset = 0; while (offset < bytesReturned) { FILE_NOTIFY_INFORMATION* pNotifyInfo = (FILE_NOTIFY_INFORMATION*)(buffer.data() + offset); std::wstring fileNameW(pNotifyInfo->FileName, pNotifyInfo->FileNameLength / sizeof(wchar_t)); std::string fileName = WStringToString(fileNameW); switch (pNotifyInfo->Action) { case FILE_ACTION_ADDED: std::cout << "File added: " << fileName << std::endl; break; case FILE_ACTION_REMOVED: std::cout << "File removed: " << fileName << std::endl; break; case FILE_ACTION_MODIFIED: std::cout << "File modified: " << fileName << std::endl; break; case FILE_ACTION_RENAMED_OLD_NAME: std::cout << "File renamed (old name): " << fileName << std::endl; break; case FILE_ACTION_RENAMED_NEW_NAME: std::cout << "File renamed (new name): " << fileName << std::endl; break; default: std::cout << "Unknown action: " << pNotifyInfo->Action << std::endl; break; } if (pNotifyInfo->NextEntryOffset == 0) { break; } offset += pNotifyInfo->NextEntryOffset; } // 重新调用 ReadDirectoryChangesW 准备下一次监控 success = ReadDirectoryChangesW( hDirectory, buffer.data(), bufferSize, TRUE, FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_LAST_ACCESS | FILE_NOTIFY_CHANGE_CREATION | FILE_NOTIFY_CHANGE_SECURITY, &bytesReturned, &overlapped, NULL ); if (!success) { std::cerr << "ReadDirectoryChangesW failed: " << GetLastError() << std::endl; break; } } else { std::cerr << "WaitForSingleObject failed: " << GetLastError() << std::endl; break; } } CloseHandle(hDirectory); CloseHandle(overlapped.hEvent); return 0; }
缓冲区中的事件信息以
FILE_NOTIFY_INFORMATION
结构体数组的形式存在。typedef struct _FILE_NOTIFY_INFORMATION { DWORD NextEntryOffset; DWORD Action; DWORD FileNameLength; WCHAR FileName[1]; // 变长数组 } FILE_NOTIFY_INFORMATION, *PFILE_NOTIFY_INFORMATION;
-
NextEntryOffset
:指向下一个FILE_NOTIFY_INFORMATION
结构体的偏移量,如果为 0,表示这是最后一个事件。 -
Action
:发生的事件类型,比如FILE_ACTION_ADDED
、FILE_ACTION_REMOVED
等。常用的 Action 如下表:Action 含义 FILE_ACTION_ADDED
文件被添加 FILE_ACTION_REMOVED
文件被删除 FILE_ACTION_MODIFIED
文件被修改 FILE_ACTION_RENAMED_OLD_NAME
文件被重命名 (旧名称) FILE_ACTION_RENAMED_NEW_NAME
文件被重命名 (新名称) -
FileNameLength
:文件名长度(以字节为单位)。 -
FileName
:文件名(宽字符)。
-
-
关闭句柄: 使用
CloseHandle
函数关闭目录句柄和事件句柄。CloseHandle(hDirectory); CloseHandle(overlapped.hEvent);
完整示例:
上面的代码已经是一个完整的示例了。
编译和运行:
- 创建一个目录
C:watched_directory
。 - 将代码保存为
ReadDirectoryChangesW_example.cpp
。 - 使用 Visual Studio 或者其他 C++ 编译器编译。
- 运行程序。
然后,你可以尝试在 C:watched_directory
目录下创建、删除或修改文件,看看程序是否能正确地检测到这些事件。
ReadDirectoryChangesW
的限制:
- 缓冲区大小: 缓冲区的大小会影响可以接收的事件数量。如果缓冲区太小,可能会导致事件丢失。
- Overlapped I/O: 使用 Overlapped I/O 需要小心处理同步问题。
- 性能: 递归监控大量目录可能会影响性能。
总结
inotify
和 ReadDirectoryChangesW
都是强大的文件系统事件监控工具。 选择哪个取决于你的操作系统和具体需求。希望今天的讲解能帮助你更好地理解和使用这两个工具,让你的程序更加“耳聪目明”!下次再见!