c++如何实现文件实时监控_监控文件修改与变化通知【进阶】

老伟大大_4085

老伟大大_4085

2026-04-12

905人浏览

原创

inotify是linux内核原生的轻量级文件监控机制,需手动递归添加子目录watch、按event->len解析事件、避免缓冲区溢出,并用inotify_init1(in_cloexec)防fd泄漏。

c++如何实现文件实时监控_监控文件修改与变化通知【进阶】

Linux 下用 inotify 实现文件变更实时通知

inotify 是 Linux 内核原生支持的轻量级文件系统事件监控机制,比轮询高效得多,且能精确捕获 IN_MODIFY、IN_CREATE、IN_DELETE 等细粒度事件。它不依赖第三方库,只需系统头文件和标准 C++(C++11 足够)。

常见错误是直接监听目录却忽略子目录递归——inotify_add_watch 默认不递归,需对每个子目录单独添加 watch;另一个坑是读取 inotify_event 时未按 len 字段截断,导致读到后续乱码或崩溃。

  • 使用 inotify_init1(IN_CLOEXEC) 创建实例,避免 fork 后 fd 泄漏
  • 对目标路径调用 inotify_add_watch(fd, path.c_str(), IN_MODIFY | IN_CREATE | IN_DELETE | IN_MOVED_TO),注意返回值为 watch descriptor(wd),非 0 才有效
  • 用 read() 一次性读满缓冲区(建议 4096 字节),再用 reinterpret_cast<const inotify_event>(buf)</const> 遍历解析,每次偏移 += sizeof(inotify_event) + event->len
  • 若需监控整个目录树,先用 std::filesystem::recursive_directory_iterator(C++17)遍历所有子目录,逐个 inotify_add_watch

Windows 上用 ReadDirectoryChangesW 避免句柄泄漏

Windows 没有 inotify 对等物,ReadDirectoryChangesW 是唯一可靠方案,但它基于异步 I/O,容易因忘记调用 CancelIoEx 或重复 CloseHandle 导致句柄泄露甚至蓝屏(尤其在服务进程里)。

它不返回具体修改了哪行内容,只告诉你“某个文件被写入”或“重命名”,且必须搭配 OVERLAPPED 和事件/完成端口使用——同步模式(NULL overlapped)会阻塞线程,不适合长期运行程序。

C++14
C++14

C++14 对 C++11 的修正与增强版本,适合旧系统维护和较老工具链兼容。

下载
  • 创建监听句柄时用 CreateFileW(path.c_str(), FILE_LIST_DIRECTORY, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED, nullptr)
  • 分配固定大小缓冲区(如 8192 字节),每次调用前重置 OVERLAPPED.hEvent,并用 WaitForSingleObject 等待事件触发
  • 解析返回数据时,必须用 FILE_NOTIFY_INFORMATION 结构体链式遍历:从缓冲区起始地址开始,每次跳转 NextEntryOffset,直到该字段为 0
  • 每次成功读取后,必须重新发起一次 ReadDirectoryChangesW 调用,否则监听会中断

跨平台封装要注意事件丢失与缓冲区溢出

inotify 和 ReadDirectoryChangesW 都可能丢事件:inotify 缓冲区满时内核会丢弃新事件并设置 IN_Q_OVERFLOW;Windows 的缓冲区溢出则直接失败并返回 ERROR_NOTIFY_ENUM_DIR。两者都不保证 100% 可靠,尤其是高频率小文件写入场景(如日志轮转、编译输出)。

不要试图在回调里做耗时操作(比如解析 JSON 或上传网络),应把事件推入队列由工作线程处理;更关键的是,必须定期检查是否发生溢出,并触发全量扫描兜底——比如记录上次扫描时间戳,一旦发现溢出就用 std::filesystem::last_write_time 对比所有文件。

  • inotify 建议设缓冲区大小为 fcntl(fd, F_SETPIPE_SZ, 1048576)(1MB),但需 root 权限才能突破默认限制
  • Windows 缓冲区至少 4KB,但频繁小变更建议 64KB 起步,否则极易溢出
  • 所有事件结构体中的文件名都是宽字符(Windows)或原始字节(Linux),不可直接当 C 字符串用,需显式加 \0 截断
  • 监控符号链接时,inotify 默认跟踪目标文件;Windows 则默认跟踪链接本身,需用 FILE_FLAG_OPEN_REPARSE_POINT 控制

C++17 std::filesystem 不适合实时监控

std::filesystem 没有监听能力,它只是封装了 stat/fstat 等系统调用,任何“用 last_write_time 定时轮询”的做法都属于伪实时——延迟取决于轮询间隔,CPU 占用高,且无法区分 chmod 和 write 这类语义差异。

有人试图用 std::filesystem::directory_iterator 配合 std::this_thread::sleep_for 实现“轻量监控”,这在开发机上可能凑合,但在容器环境或高负载服务器上,两次轮询间可能错过数十次变更,且无法响应 IN_MOVED_FROM 这类原子操作事件。

  • 轮询最小间隔别低于 100ms,否则大量 stat 系统调用会拖慢整个存储栈
  • 若真要用轮询,至少缓存 inode+size+mtime 三元组,避免仅靠时间戳误判(NFS/VM 共享盘时间不同步)
  • 绝对不要在主线程里轮询并 sleep,应放到独立 std::thread 并设 std::this_thread::yield() 防止抢占式调度失衡
实际部署时最易被忽略的是权限与路径生命周期:inotify watch 在目标文件被 unlink 后依然存在,但 wd 不再有效;Windows 句柄在目录被删除后立即失效,且不会自动重建。监控逻辑必须能感知路径消失并主动重注册,而不是静默失败。

C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!

相关文章

c++速学教程(入门到精通)
c++速学教程(入门到精通)

c++怎么学习?c++怎么入门?c++在哪学?c++怎么学才快?不用担心,这里为大家提供了c++速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

c++

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
json数据格式
json数据格式

JSON是一种轻量级的数据交换格式。本专题为大家带来json数据格式相关文章,帮助大家解决问题。

2023.08.07

2175

5

json是什么
json是什么

JSON是一种轻量级的数据交换格式,具有简洁、易读、跨平台和语言的特点,JSON数据是通过键值对的方式进行组织,其中键是字符串,值可以是字符串、数值、布尔值、数组、对象或者null,在Web开发、数据交换和配置文件等方面得到广泛应用。本专题为大家提供json相关的文章、下载、课程内容,供大家免费下载体验。

2023.08.23

3382

1

jquery怎么操作json
jquery怎么操作json

操作的方法有:1、“$.parseJSON(jsonString)”2、“$.getJSON(url, data, success)”;3、“$.each(obj, callback)”;4、“$.ajax()”。更多jquery怎么操作json的详细内容,可以访问本专题下面的文章。

2023.10.13

1136

3

go语言处理json数据方法
go语言处理json数据方法

本专题整合了go语言中处理json数据方法,阅读专题下面的文章了解更多详细内容。

2025.09.10

3899

7

c语言中null和NULL的区别
c语言中null和NULL的区别

c语言中null和NULL的区别是:null是C语言中的一个宏定义,通常用来表示一个空指针,可以用于初始化指针变量,或者在条件语句中判断指针是否为空;NULL是C语言中的一个预定义常量,通常用来表示一个空值,用于表示一个空的指针、空的指针数组或者空的结构体指针。

2023.09.22

549

3

java中null的用法
java中null的用法

在Java中,null表示一个引用类型的变量不指向任何对象。可以将null赋值给任何引用类型的变量,包括类、接口、数组、字符串等。想了解更多null的相关内容,可以阅读本专题下面的文章。

2024.03.01

1698

6

c语言const用法
c语言const用法

const是关键字,可以用于声明常量、函数参数中的const修饰符、const修饰函数返回值、const修饰指针。详细介绍:1、声明常量,const关键字可用于声明常量,常量的值在程序运行期间不可修改,常量可以是基本数据类型,如整数、浮点数、字符等,也可是自定义的数据类型;2、函数参数中的const修饰符,const关键字可用于函数的参数中,表示该参数在函数内部不可修改等等。

2023.09.20

2258

7

js 字符串转数组
js 字符串转数组

js字符串转数组的方法:1、使用“split()”方法;2、使用“Array.from()”方法;3、使用for循环遍历;4、使用“Array.split()”方法。本专题为大家提供js字符串转数组的相关的文章、下载、课程内容,供大家免费下载体验。

2023.08.03

1778

5

js截取字符串的方法
js截取字符串的方法

js截取字符串的方法有substring()方法、substr()方法、slice()方法、split()方法和slice()方法。本专题为大家提供字符串相关的文章、下载、课程内容,供大家免费下载体验。

2023.09.04

2804

5

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
C++ Core Guidelines
C++ Core Guidelines

共0课时 | 0人学习

C++ Reference
C++ Reference

共0课时 | 0人学习

C++ 官方标准说明
C++ 官方标准说明

共0课时 | 0人学习