之前开发一些Linux程序的时候,想要监控文件或者文件夹被改动的事件,但是没有找到方法。今天在看Linux/UNIX系统编程手册这本书的时候,看到有一章专门讲监控文件事件,才顿悟自己还是看书看的太少了。因此写这部博客记录一下,后续若用到,也好马上用到。
从内核2.6.13起,Linux就提供了inotify机制,以允许应用程序监控文件事件。inotify主要有以下API:
int inotify_init(void):创建一个新的inotify实体,该调用返回一个fd文件句柄
int inotify_add_watch(int fd, const char *pathname, uint32_t mask):将pathname路径添加到监控列表,其中fd是inotify_init时返回的值,mask是要监控的事件掩码。该调用返回一个wd句柄。mask包含的事件见下面的表
int inotify_rm_watch(int fd, uint32_t wd):将inotify_add_watch返回生成的wd,从inotify实例中移除监控。删除监控会生成一个IN_IGNORED事件。
还有一个结构体
struct inotify_event{
int wd; /*Watch descriptor on which event occurred*/
uint32_t mask; /*Bts desccribing event that occurred */
uint32_t cookie; /* cookieforrelatedevents(forrename()) */
uint32_t len; /* Size of 'name' field*/
char name[]; /* Optional null-terminated filename */
}
示例代码如下:
#include <sys/inotify.h> /*这个是inotify API的头文件,必须引用*/
#include <limits.h>
#include <stdlib.h>
#include <stdio.h>
#define BUF_LEN (10 * (sizeof(struct inotify_event)) + NAME_MAX + 1)
static void displayInotifyEvent(struct inotify_event *event)
{
if(event->cookie > 0)
printf(" cookie = %4d", event->cookie);
printf("mask or event:");
if(event->mask & IN_ACCESS) printf("IN_ACCESS ");
if(event->mask & IN_ATTRIB) printf("IN_ATTRIB ");
if(event->mask & IN_CLOSE_NOWRITE) printf("IN_CLOSE_NOWRITE");
if(event->mask & IN_CLOSE_WRITE) printf("IN_CLOSE_WRITE");
if(event->mask & IN_CREATE) printf("IN_CREATE");
if(event->mask & IN_DELETE) printf("IN_DELETE");
if(event->mask & IN_MODIFY) printf("IN_MODIFY");
if(event->mask & IN_OPEN) printf("IN_OPEN");
printf("\n");
if(event->len > 0)
printf(" name=%s\n", event->name);
}
int main(){
int ret = -1;
int notify_handle = -1;
int notify_add_handle = -1;
struct inotify_event *event;
char *p;
char buf[BUF_LEN];
notify_handle = inotify_init1(IN_NONBLOCK);
printf("inotify_init ret:%d!\n", notify_handle);
notify_add_handle = inotify_add_watch(notify_handle, "testdir", IN_ALL_EVENTS/*IN_ATTRIB | IN_ACCESS | IN_MODIFY | IN_OPEN*/);
while(1){
int num = read(notify_handle, buf, BUF_LEN);
for(p=buf; p<buf+num;)
{
event = (struct inotify_event *)buf;
displayInotifyEvent(event);
p+=sizeof(struct inotify_event) + event->len;
usleep(500*1000);
}
}
return 0;
}
编译运行后,就可以监控同级目录下的testdir目录了。当testdir目录有文件生成、修改、删除时。read就可以读到该事件的缓冲数据,对缓冲数据进行解析,就可以得到具体的事件了。
下表是inotify对应的监控事件
IN_ACCESS 文件被访问(read())
IN_ATTRIB 文件元数据改变
IN_CLOSE_WRITE 关闭为写入而打开的文件
IN_CLOSE_NOWRITE 关闭以只读方式打开的文件
IN_CREATE 在受监控目录内创建文件/目录
IN_DELETE 在受监控目录内删除文件/目录
IN_DELETE_SELF 删除受监控目录/文件本身
IN_MODIFY 文件被修改
IN_MOVE_SELF 移除受监控文件/文件夹本身
IN_MOVED_FROM 文件移出到受监控目录之外
IN_MOVED_TO 将文件移入受监控目录
IN_OPEN 文件被打开
IN_ALL_EVENTS 上面事件的统称
IN_MOVE IN_MOVED_FROM | IN_MOVED_TO的事件统称
IN_CLOSE IN_CLOSE_WRITE|IN_CLOSE_NOWRITE的统称
IN_DONT_FOLLOW 不对符号链接解引用
IN_MASK_ADD 将事件追加到pathname的当前监控掩码
IN_ONESHOT 只监控pathname的一个事件
IN_ONLYDIR pathname不为目录时会失败
IN_IGNORED 监控项为内核或应用程序所移除
IN_ISDIR name中所返回的文件名为路径
IN_Q_OVERFLOW 事件队列溢出
IN_UNMOUNT 包含对象的文件操作系统遭卸载