如何配置inotify事件掩码实现文件读写各触发单次通知?
Inotify单次触发读写通知的正确配置
问题原因拆解
- 为什么
IN_MODIFY会导致写入通知触发两次?
参考给出的strace输出,执行echo "hello" > ./a.txt时,会先后两次修改文件:第一次是openat带O_TRUNC标志将文件截断为0长度,触发第一次IN_MODIFY;第二次是实际调用write写入文件内容,触发第二次IN_MODIFY,因此才会打印两次日志。 - 为什么配置
IN_CLOSE_WRITE|IN_ACCESS后收不到写入通知?
这不是掩码的问题,是参考代码的逻辑缺陷:inotify_event结构体的len字段,只有当监控目标是目录、事件对应目录下的子文件时,才会携带非零值(用来表示事件附带的文件名字符串长度);当你直接监控单个文件本身时,所有事件的len恒为0,代码里if(event->len)的判断会直接把有效事件过滤掉,根本走不到打印分支。
正确配置方案
- 掩码替换为
IN_CLOSE_WRITE | IN_ACCESS
两个事件的触发逻辑完全匹配需求:IN_CLOSE_WRITE:当以可写模式打开的文件被最终关闭时才触发,覆盖从文件打开、截断、写入到关闭的全流程,不管中间触发多少次文件修改操作,最终只在写入完成后发1次通知,完全避免重复触发IN_ACCESS:当文件被读取操作访问时触发,对应cat命令的场景
- 修复代码中的事件过滤bug
去掉if(event->len)的判断逻辑——因为监控单个文件时你已经明确知道被监控的目标路径,不需要从事件结构里读取文件名,更不能用len字段做事件过滤。
修改后的核心代码片段
- 注册监控时的掩码配置:
wd = inotify_add_watch(fd, path_to_be_watched, IN_CLOSE_WRITE | IN_ACCESS);
- 事件处理逻辑:
while(i<length){ event = (struct inotify_event *) &buffer[i]; // 去掉if(event->len)的过滤判断 if ( event->mask & IN_CLOSE_WRITE ) { printf( "The file was modified (write completed).\n" ); } else if ( event->mask & IN_ACCESS ) { printf( "The file was accessed.\n" ); } i += EVENT_SIZE + event->len; }
效果验证
- 执行
echo "xyz" > /tmp/the_file时,仅在文件写入完成、句柄关闭时触发1次写入通知 - 执行
cat /tmp/the_file时,触发1次读取访问通知
内容的提问来源于stack exchange,提问作者Edmund
相关产品推荐
相关产品推荐

