Inotify,它是在内核 2.6.13 版本中引入的一个新功能,它为用户态监视文件系统的变化提供了强大的支持,允许监控程序打开一个独立文件描述符,并针对事件集监控一个或者多个文件,例如打开、关闭、移动/重命名、删除、创建或者改变属性。
在inotify 的前身是 dnotify。由于 dnotify 的局限性太大,加之用户始终都希望用到更好的产品。因此,inotify 顺理成章的取代了 dnotify。
inotify 取代 dnotify 的原因有哪些呢?
1、Inotify 使用一个独立的文件描述符,而 dnotify 需要为每个受监控的目录打开一个文件描述符。当你同时监控多个目录时,就会消耗大量的资源,因此成本会非常高,而且还会遇到每个进程文件描述符数量的限制。
2、Inotify 所使用的文件描述符可以通过系统调用获得,并且没有相关设备或者文件。而 dnotify 在使用时,文件描述符会锁定目录,导致设备无法卸载,这是可移动媒体的一个典型问题。在使用 inotify 时,如果正在监控被卸载的文件系统上的文件,那么 watch 会被自动移除,并且您会接收到一个 umount 事件。
3、dnotify 的设计过于复杂。inotify 能够监视文件或者目录,而使用 dnotify时,监控粒度只停留于目录级别。为了使 dnotify 能够进行更细粒度的监控,应用程序编程人员必须为每个受监控的目录保留一个 stat 结构的缓存。该用户空间的 stat 结构缓存需要用来明确确定当接收到通知信号时,目录发生了什么变化。当获得通知信号时,生成 stat 结构列表并与最新的状态相比较。很明显,这种技术是不太理想的。
4、inotify 使用文件描述符作为基本接口,允许应用程序开发者使用 select 和 poll来监控设备,并且允许高效的多路 I/O 和与 Glib 的mainloop 的集成。相反,dnotify 所使用的 SIGIO 常常使程序员头疼并且感觉不太优雅。在 2.6.25 内核中 inotify 还添加了 Signal-drive I.O 通知功能。
由于 inotify 是内核中的功能,因此为了让用户态更方便的去使用到它,它通过提供一个更优雅的 API 来解决了这些问题。该 API 使用最少的文件描述符,并确保更细粒度的监控,与 inotify 的通信是通过设备节点提供的。
推荐阅读:
inotify-tools+rsync实时同步文件安装和配置
下面,列举 inotify 中可用的函数:
inotify_init # 用于创建一个 inotify 实例的系统调用,并返回一个指向该实例的文件描述符
inotify_init1与 # inotify_init 相似,并带有附加标志。如果这些附加标志没有指定,将采用与 inotify_init 相同的值
inotify_add_watch # 增加对文件或者目录的监控,并指定需要监控哪些事件。标志用于控制是否将事件添加到已有的监控中,是否只有路径代表一个目录才进行监控,是否要追踪符号链接,是否进行一次性监控,当首次事件出现后就停止监控
inotify_rm_watch # 从监控列表中移出监控项目
read # 读取包含一个或者多个事件信息的缓存
close # 关闭文件描述符,并且移除所有在该描述符上的所有监控。当关于某实例的所有文件描述符都关闭时,资源和下层对象都将释放,以供内核再次使用
因此,一个典型的监控程序需要进行如下操作:
1 使用 inotify_init 打开一个文件描述符
2 添加一个或者多个监控
3 等待事件
4 处理事件,然后返回并等待更多事件
5 当监控不再活动时,或者接到某个信号之后,关闭文件描述符,清空,然后退出。
可监控的事件
作为文件系统事件监控机制,到底有哪些事件能够被监控呢?
下面为大家列举,inotify所能监控的事件标志如下:
IN_ACCESS 被监控项目或者被监控目录中的条目被访问过。例如,一个打开的文件被读取。
IN_MODIFY 被监控项目或者被监控目录中的条目被修改过。例如,一个打开的文件被修改。
IN_ATTRIB 被监控项目或者被监控目录中条目的元数据被修改过。例如,时间戳或者许可被修改。
IN_CLOSE_WRITE 一个打开的,等待写入的文件或目录被关闭。
IN_CLOSE_NOWRITE 一个以只读方式打开的文件或目录被关闭。
IN_CLOSE 一个掩码,可以很便捷地对前面提到的两个关闭事件(IN_CLOSE_WRITE | IN_CLOSE_NOWRITE)进行逻辑操作。
IN_OPEN 文件或目录被打开。
IN_MOVED_FROM 被监控项目或者被监控目录中的条目被移出监控区域。该事件还包含一个 cookie 来实现 IN_MOVED_FROM 与 IN_MOVED_TO 的关联。
IN_MOVED_TO 文件或目录被移入监控区域。该事件包含一个针对 IN_MOVED_FROM 的 cookie。如果文件或目录只是被重命名,将能看到这两个事件,如果它只是被移入或移出非监控区域,将只能看到一个事件。如果移动或重命名一个被监控项目,监控将继续进行。参见下面的 IN_MOVE-SELF。
IN_MOVE 可以很便捷地对前面提到的两个移动事件(IN_MOVED_FROM | IN_MOVED_TO)进行逻辑操作的掩码。
IN_CREATE 在被监控目录中创建了子目录或文件。
IN_DELETE 被监控目录中有子目录或文件被删除。
IN_DELETE_SELF 被监控项目本身被删除。监控终止,并且将收到一个 IN_IGNORED 事件。
IN_MOVE_SELF 监控项目本身被移动。
除了事件标志以外,还可以在 inotify 头文件(/usr/include/sys/inotify.h)中找到其他几个标志。
例如,如果只想监控第一个事件,可以在增加监控时,设置 IN_ONESHOT 标志。