linux inotify机制

1、inotify主要功能

它是一个内核用于通知用户空间程序文件系统变化的机制。

inotify是文件系统变化通知机制,在监听到文件系统变化后,会向相应的应用程序发送事件。典型的应用场景是文件管理器,理想情况下是用户修改了文件内容后立刻显示出文件最新的内容,如果没有inotify机制,一般会采用轮询的方式实现这种功能,这不能再第一时间反应文件系统的变化,而且浪费CPU时间。

2. 系统调用

与 inotify 有关的系统调用主要有三个:inotify_initinotify_add_watchinotify_rm_watch,具体的系统调用如下所示:

int fd = inotify_init();

inotify_init创建一个inotify实例,该函数会返回文件描述符用来指代inotify实例,同时之后需要通过对该文件描述符进行read 操作获取文件变更事件。

int wd = inotify_add_watch(fd, path, mask);
  • fd 指代 inotify_init 系统调用返回的 notify 实例
  • pathname 指代需要被监听事件的文件或者目录路径
  • mask 事件掩码,表明需要监听的事件类型。

该系统调用返回值(wd)是监控描述符,指代一条监控项。

int ret = inotify_rm_watch(fd, wd);
  • fd 指代 inotify_init 系统调用返回的 notify 实例
  • wd 指代监控项描述符

3、事件类型

1.常规事件类型

mask 标志描述
IN_ACCESS文件被访问(执行了 read 操作)
IN_ATTRIB文件元数据发生变更
IN_CLOSE_WRITE关闭为了写入而打开的文件
IN_CLOSE_NOWRITE关闭以只读方式打开的文件
IN_CREATE在受控目录内创建了文件或者目录
IN_DELETE在受控目录内删除了文件或者目录
IN_DELETE_SELF删除受控文件或者目录本身
IN_MOVED_FROM文件移出受控目录之外
IN_MOVED_TO文件移入受控目录
IN_OPEN文件被打开
IN_MOVEIN_MOVED_FROM|IN_MOVED_TO 事件的统称
IN_CLOSEIN_CLOSE_WRITE|IN_CLOSE_NOWRITE 统称
  • IN_ATTRIB监控的元数据变更包括,权限,所有权,链接数,用户 ID 等
  • 重命名受控对象时会发出IN_DELETE_SELF事件,而如果受控目标是一个目录,那么受控目标下的文件发生重命名时会触发两个事件IN_MOVED_FROMIN_MOVED_TO

在我们的日常开发工作中,上述事件已经基本涵盖了文件变更的所有情况。我们可以按照各自的场景,针对上述不同的事件类型做出相应的处理流程。

2. 其他事件

除了上述文件的常规事件外,inotify还提供了以下几个 mask 来控制事件监听的过程

mask 标志描述
IN_DONT_FOLLOW不对符号链接引用
IN_MASK_ADD将事件追加到 pathname 的当前监控掩码
IN_ONESHOT只监控 pathname 的一个事件
IN_ONLYDIRpathname 不为目录时会失败

将上述 mask 标志添加到 inotify_add_watch 中时可以控制监听过程,这么说有点笼统,举个例子来说。

inotify_add_watch(fd, pathname, IN_OPEN | IN_CLOSE | IN_ONESHOT);

上面这段代码,除了监听文件的 IN_OPENIN_CLOSE事件外,还添加了 IN_ONESHOT mask,那么这就意味着,当监听到 pathname 所指代的文件一次事件后 inotify就不会在监听 pathname 所指代的文件发出的事件了。

上述 mask 是在添加某个文件监控项的时候作为inotify_add_watch系统调用的参数传入的。除此之外还有以下几个事件,这些事件不需要用户显示调用inotify_add_watch添加,仅当出现一些其他异常情况时发出。

mask 标志描述
IN_IGNORED监控项为内核或者应用程序移除
IN_ISDIR被监听的是一个目录的路径
IN_Q_OVERFLOW事件队列溢出
IN_UNMOUNT包含对象的文件系统遭到卸载
  • IN_ISDIR事件表明被监听的 pathname 指代的是一个目录,举例来说 mkdir /tmp/xxx 这个系统命令会产生 IN_CREATE|IS_DIR 事件。

4、事件结构

上文描述了inotify支持的事件类型,可以看出来支持的事件类型非常丰富,基本满足了我们对于文件监听的各种诉求。除了上述的事件类型外,在这一小节我们会简单描述一下inotifyevent结构,通过事件的数据结构可以看出,从事件中我们可以获取到哪些信息。事件的具体数据结构如下:

struct inotify_event {
    int		    wd;  	//监控描述符号,唯一指代一个监控项目
  	uint32_t	mask;	//监控的事件类型
  	uint32_t	cookie;	//只有重命名才会使用到该字段
  	uint32_t	len;	//下面 name 数组的尺寸
  	char		name[];	//当受控目录下的文件有变更时,该字符串会记录发生变更的文件的文件名
};

5、示例代码

#include <stdio.h>
#include <sys/inotify.h>
#include <sys/select.h>
#include <unistd.h>

int main() {
	char* filePath = "/dev/input";
	for (;;) {
		int mINotifyFd = inotify_init();
		printf("mINotifyFd=%d\n", mINotifyFd);
		int result = inotify_add_watch(mINotifyFd, filePath, IN_ALL_EVENTS);
		printf("inotify_add_watch result=%d\n", result);
		fd_set fds;
		FD_ZERO(&fds);
		FD_SET(mINotifyFd, &fds);
		unsigned char buffer[1024] = { 0 };
		if (select(mINotifyFd + 1, &fds, NULL, NULL, NULL) > 0) {
			int length = read(mINotifyFd, buffer, sizeof(buffer));
			int offset = 0;
			while (offset <= length) {
				struct inotify_event* event = (struct inotify_event*)(buffer + offset);
				printf("event->name:%s\n", event->name);
				if (event->mask & IN_ACCESS) {
					printf("IN_ACCESS\n");
				}
				if (event->mask & IN_OPEN) {
					printf("IN_OPEN\n");
				}
				if (event->mask & IN_CLOSE) {
					printf("IN_CLOSE\n");
				}
				offset += sizeof(struct inotify_event) + event->len;
			}
		}
	}
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值