Inotify——实现Linux文件系统的监控
Inotify是Linux中用于监控文件系统变化的API,该API可以实现用非轮询的方式,近似实时地监控目录或文件发生的变化。
Inotify简介
Inotify是Linux中用于监控文件系统变化的API,自Linux 2.6.13开始集成到Linux内核中,并取代了以往的dnotify。该API可以实现用非轮询的方式,近似实时地监控目录或文件发生的变化。
利用Inotify可以十分方便地实现诸如文件实时同步、目录索引自动更新、配置文件自动重加载等功能。在Linux中可以通过man 7 inotify查阅Inotify的手册。
API使用简介
Inotify API由头文件<sys/inotify.h>提供,其中包括函数
inotify_init() inotify_init1() inotify_add_watch() inotify_rm_watch()。
inotify_init()和inotify_init1()功能相似,若成功调用可以初始化一个inotify的实例,并返回一个用于读取文件系统事件的文件描述符,若失败则会返回-1。
不同之处在于,后者提供了一个参数。当传入0时,二者没有区别,但传入IN_NONBLOCK IN_CLOEXEC掩码后会对返回的文件描述符提供额外的控制功能,这两个掩码分别提供与fcntl()中的O_NONBLOCK和open()中的FD_CLOEXEC相似的功能,在此不对这两个掩码的功能作详细介绍。
在成功调用inotify_init()或inotify_init1()后,其返回值作为文件描述符,可在后续使用read()系统调用来读取文件系统监控事件的信息,并且该读取是阻塞式的,当没有事件发生时,read()将不会返回。
inotify_add_watch()和inotify_rm_watch()分别用于从监控列表中添加和删除目录/文件项。inotify_add_watch()接受参数为inotify实例的文件描述符、需要监控的目标文件/目录路径,以及需要监控的事件掩码,成功调用后返回一个监控描述符(Watch descriptor),对应于目标路径在文件系统中的inode对象,若失败则会返回-1并设置errno。inotify_rm_watch()接受参数为inotify实例的文件描述符和监控文件或目录的监控描述符,可以停止监控对应的文件或目录。
对于一个文件或目录,可以使用位或运算符合并掩码来同时监控多个事件。可监控事件列表如下:
事件类型
常规事件类型

| 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_MOVE | IN_MOVED_FROM|IN_MOVED_TO 事件的统称 |
| IN_CLOSE | IN_CLOSE_WRITE|IN_CLOSE_NOWRITE 统称 |
- IN_ATTRIB监控的元数据变更包括,权限,所有权,链接数,用户 ID 等
重命名受控对象时会发出IN_DELETE_SELF事件,而如果受控目标是一个目录,那么受控目标下的文件发生重命名时会触发两个事件IN_MOVED_FROM和IN_MOVED_TO
在我们的日常开发工作中,上述事件已经基本涵盖了文件变更的所有情况。我们可以按照各自的场景,针对上述不同的事件类型做出相应的处理流程。
其他事件
除了上述文件的常规事件外,inotify还提供了以下几个 mask 来控制事件监听的过程
| mask 标志 | 描述 |
|---|---|
| IN_DONT_FOLLOW | 不对符号链接引用 |
| IN_MASK_ADD | 将事件追加到 pathname 的当前监控掩码 |
| IN_ONESHOT | 只监控 pathname 的一个事件 |
| IN_ONLYDIR | pathname 不为目录时会失败 |
将上述 mask 标志添加到 inotify_add_watch中时可以控制监听过程,这么说有点笼统,举个例子来说。
inotify_add_watch(fd, pathname, IN_OPEN | IN_CLOSE | IN_ONESHOT);
上面这段代码,除了监听文件的 IN_OPEN和IN_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事件。
在设置监控成功后,通过read()系统调用从inotify实例提供的文件描述符中读取文件系统监控事件的信息,该信息使用inotify_event结构体来记录,该结构体的声明如下:
|
示例代码
|
更多推荐


所有评论(0)