最近在写一个云备份的项目,其中有一个模块是要监控计算机本地的文件,于是我翻了翻linux/unix系统编程手册发现了inotify这个用于文件监控的框架
1)inotify机制可用于监控文件或目录。当监控目录时,与该目录自身以及该目录下面的文件都会被监控,其上有事件发生时都会通知给应用程序
2)inotify监控机制为非递归,若应用程序有意监控整个目录子树内的事件,则需对该树中的每个目录发起inotify_add_watch()调用
3)可使用select(),poll(),epoll()以及由信号驱动的I/O来监控inotify文件描述符
1)inotify_init()系统调用可创建一新的inotify实例
#include<sys/inotify.h> int inotify_init(void);
2)针对fd所指的inotify实例的监控列表,系统调用inotify_add_watch()可以追加新的监控项
#include<sys/inotify.h> int inotify_add_watch(int fd,const char *pathname,uint32_t mask);
参数mask为一位掩码,针对pathname定义了想要监控的事件,此函数的返回值为一个用于唯一指代此监控项的描述符
IN_ACCESS 文件被访问
IN_ATTRIB 文件元数据改变
IN_CLOSE_WRITE 关闭为了写入而打开的文件
IN_CREATE 在受监控目录下创建了文件或目录
IN_DELETE 在受监控目录内删除了文件或目录
IN_DELETE_SELF 删除了受监控目录/文件本身
IN_MODIFY 文件被修改
IN_MODIFY_SELF 移动受监控目录或文件本身
IN_MOVED_FROM 文件移除受监控目录
IN_MOVED_TO 将文件移到受监控目录
IN_OPEN 文件被打开
IN_ALL_EVENTS 以上所有输出事件的统称
IN_MOVE IN_MOVED_FROM | IN_MOVED_TO事件的统称
IN_ONESHOT 只监控pathname的一个事件
IN_ONLYDIR pathname不为目录时会失败
对于上述一些事件的说明:
1)当文件的元数据(比如,权限,所有权,链接计数,扩展属性,用户ID,或组ID等)改变时,会发生IN_ATTRIB事件
2)删除受监控对象时会发生IN_DELETE_SELF
3)重命名对象时会发生IN_MORE_SELF事件
4)ONE_SHOT允许只监控pathname的一个事件,事件发生后,监控项会自动从监控列表消失
将监控项项在监控列表中登记后,应运程序可用read()从inotify的文件描述符中读取事件,以判定发生了那些事件。若读取之时还没有发生任何事件,则read()会阻塞,直至有事件产生,事件发生后,每次调用read()会返回一个缓存区,内含一个或多个如下类型的结构体
struct inotify_event { <span style="white-space:pre"> </span>int wd;
<span style="white-space:pre"> </span>uint32_t mask;
<span style="white-space:pre"> </span>uint32_t cookie;
<span style="white-space:pre"> </span>uint32_t len;
<span style="white-space:pre"> </span>char name[]; }.字段wd指名发生事件的是哪个监控描述符,该字段值由之前对inotify_add_watch()的调用返回。因为用read()读到的是inotify文件中的所有事件,可是当inotify同时监控多个目录或文件时我们应该如何区分读到的内容呢,这是wd就派上了用场,我们可以用wd来做区分
.mask字段返回了描述该事件的位掩码
.cookie字段将相关事件联系到一起,目前只有对重命名时才会用到
.len字段表示实际分配给name字段的字节数
.name字段则是标示该文件
#include<stdio.h> #include<assert.h> #include<unistd.h> #include<stdlib.h> #include<errno.h> #include<string.h> #include<sys/types.h> #include<sys/inotify.h> #include<limits.h> #include<fcntl.h> #define BUF_LEN 1000 void displayInotifyEvent(struct inotify_event *i) { printf(" wd = %2d; ",i->wd); if(i->cookie > 0) { printf("cokkie = %4d; ",i->cookie); } printf("mask = "); if(i->mask & IN_ACCESS) printf("IN_ACCESS\n"); if(i->mask & IN_DELETE_SELF) printf("IN_DELETE_SELF\n"); if(i->mask & IN_MODIFY) printf("IN_MODIFY\n"); if(i->mask & IN_OPEN) printf("IN_OPEN\n"); if(len > 0) { printf("name = %s\n",i->name); } } int main(int argc,char **argv) { int inotifyFd,wd,j; char buf[BUF_LEN]; ssize_t numRead; char *p; struct inotify_event *event; int flags; if(argc < 2 ) { printf("error\n"); } inotifyFd = inotify_init(); if(inotifyFd == -1) { printf("初始化失败"); } wd = inotify_add_watch(inotifyFd,argv[1],IN_ALL_EVENTS); if(wd == -1) { printf("error\n"); } printf("Watching %s using wd %d\n",argv[1],wd); while(1) { numRead = read(inotifyFd,buf,BUF_LEN); if(numRead == -1) { printf("read error\n"); } printf("Read %ldbytes from inotify fd\n",(long)numRead); for(p=buf;p < buf+numRead;) { event = (struct inotify_event *)p; displayInotifyEvent(event); p+=sizeof(struct inotify_event) + event->len; } } return 0; }