Linux用inotify监听文件增删改需手动为子目录添加watch,注意检查inotify_add_watch返回值、合理设置max_user_watches;Windows用ReadDirectoryChangesW需设足够缓冲区、宽字符路径,并避免阻塞回调;跨平台推荐libuv但需处理事件去重与动态递归监听。

Linux下用inotify监听文件增删改
inotify是Linux内核提供的轻量级文件系统事件通知机制,适合监控单个目录或少量路径。它不递归监听子目录,需要手动为每个子目录添加watch,但开销小、响应快。
常见错误是调用inotify_add_watch后没检查返回值:返回-1表示失败,可能是权限不足(如监控/proc)、路径不存在,或超出/proc/sys/fs/inotify/max_user_watches限制。
- 用
IN_CREATE捕获新建文件,IN_DELETE捕获删除,IN_MODIFY对文件内容修改有效,但对重命名需配合IN_MOVED_TO/IN_MOVED_FROM - 每次
read()从inotify fd读取的是变长结构struct inotify_event,必须循环解析,不能假设一次read只返回一个事件 - 监听多个路径时,每个
inotify_add_watch返回唯一wd(watch descriptor),事件中的wd字段用于区分来源
Windows用ReadDirectoryChangesW轮询更可靠
Windows没有类似inotify的底层事件驱动接口,ReadDirectoryChangesW是官方推荐方案,但它本质是异步I/O,需搭配IOCP或事件对象使用,直接阻塞调用容易卡死或漏事件。
容易踩的坑是缓冲区大小设太小:默认4096字节不够,尤其在批量创建文件时会触发ERROR_NOTIFY_ENUM_DIR错误,导致事件丢失;建议至少设为8192,并检查返回值是否为TRUE(成功)或FALSE(需GetLastError()判断)。
立即学习“C++免费学习笔记(深入)”;
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
- 必须用宽字符路径(
L"C:\path"),且路径末尾不能带反斜杠 -
FILE_NOTIFY_CHANGE_LAST_WRITE能捕获内容修改,但FILE_NOTIFY_CHANGE_FILE_NAME才管新建/删除/重命名 - 不要在回调里直接处理耗时操作,应把事件推入队列由工作线程消费,否则下次
ReadDirectoryChangesW调用会被阻塞
C++跨平台封装要注意事件合并与重复
不同系统对同一操作产生的事件数量不一致:比如Linux下mv a b可能触发IN_MOVED_FROM+IN_MOVED_TO两个事件,而Windows可能只报一次FILE_ACTION_RENAMED_OLD_NAME+FILE_ACTION_RENAMED_NEW_NAME。直接按事件类型做逻辑易出错。
关键不是“收到什么事件”,而是“文件状态是否变了”。实际项目中建议加一层去重和延迟合并:对同一文件路径的连续事件(如多次IN_MODIFY)在100ms窗口内合并,再触发回调。
- 避免用
std::filesystem::last_write_time()轮询检测——它开销大且无法区分“谁改的”,仅作兜底验证 - inotify的
IN_IGNORED事件表示watch被移除(如目录被删),此时应清理对应wd记录,否则后续事件会无主可查 - Windows下
ReadDirectoryChangesW返回的FILE_NOTIFY_INFORMATION中FileNameLength是字节数,不是字符数,需除以sizeof(WCHAR)才能得到真实长度
不要用boost::filesystem::recursive_directory_iterator做实时监控
有人误以为boost::filesystem::recursive_directory_iterator能“监听”变化,其实它只是遍历快照,没有任何事件通知能力。每秒调用一次做全量比对,CPU和IO压力极大,且无法精确捕捉瞬时变更(如临时文件写完即删)。
真正需要跨平台又不想自己封装,可用libuv的uv_fs_event_t(底层在Linux走inotify,Windows走ReadDirectoryChangesW),但注意它不保证事件顺序,也不递归监听新创建的子目录——得自己监听IN_CREATE | IN_ISDIR后动态添加watch。
-
uv_fs_event_start的callback可能被多次并发调用,需确保线程安全 - macOS上libuv用kqueue,事件粒度比inotify粗,
UV_FS_EVENT_RECURSIVE需macOS 10.15+才支持 - 如果只监控配置文件,优先考虑文件mtime变化+简单校验和,比完整监听更稳

















