Linux中一切皆文件,在应用程序中,有时候我们需要对文件系统的目录或者文件进行监控,以便于我们能根据文件系统的变化来做相应的后续操作。那我们如何有效的对文件系统进行监控呢?不用苦恼,linux的前辈们已经给我们做好了,在linux2.6内核中开始引入,作为linux的系统调用来使用,所以我们就可以用它来帮助我们来完成这件事了。 接下来我们来学习一下于inotify相关的系统调用接口: int inotify_init(void); 功能:获得一个文件描述符,用于关联后续的inotify事件队列。 int inotify_add_watch(int fd, const char *pathname, uint32_t mask); 功能:在inotify文件描述符中添加新的监听对象。 参数: fd, inotify_init函数的返回值 Pathname, 添加要监听的文件或者目录的路径 Mask, 要监听的文件或者目录上发生的事件。 返回值:就是新添加监听的文件描述符。 int inotify_rm_watch(int fd, int wd); 功能:从inotify的事件队列中删除一个监听对象。 参数:fd, 监听事件描述符,就是inotify_init的返回值 wd, inotify_add_watch的返回值。 有了上边的这三个函数,我们我们就可以添加对文件或者目录的监听事件了,但是文件或者目录一旦发生了变化我们又怎么能直到呢?所以我们仅仅有他们还不够,我们还需要read函数。因为当我们添加了监听事件后,我们需要使用select或者其他的方式来监听我们的监听队列,一旦发生变化,我们就必须得用read函数读取该描述符的数据,其中的数据就包含了我们文件的变化。read的返回值就是一个或者多个struct inotify_event的结构体,结构体的定义如下: struct inotify_event { int wd; /* Watch descriptor. */ uint32_t mask; /* Watch mask. */ uint32_t cookie; /* Cookie to synchronize two events. */ uint32_t len; /* Length (including NULs) of name. */ char name __flexarr; /* Name. */ }; 示例代码如下: #define BUF_LEN 10 * (sizeof(struct inotify_event) + NAME_MAX + 1) #define WATCH_DIR_1 "/home/ys/test_1" #define WATCH_DIR_2 "/home/ys/test_2" int main(int argc, const char *argv[]) { int init_fd; int watch_fd_1, watch_fd_2; int watch_mask = IN_ALL_EVENTS; struct inotify_event *even; char buf[BUF_LEN] = {0}; char *p = NULL; ssize_t bytes; //创建监听文件描述符句柄 init_fd = inotify_init(); if (init_fd < 0) { perror("fail to inotify_init"); exit(1); } //添加监听的目录或者文件 watch_fd_1 = inotify_add_watch(init_fd, WATCH_DIR_1, watch_mask); if (watch_fd_1 < 0) { perror("fail to inotify_add_watch 111"); exit(1); } //添加监听的目录或者文件 watch_fd_2 = inotify_add_watch(init_fd, WATCH_DIR_2, watch_mask); if (watch_fd_2 < 0) { perror("fail to inotify_add_watch 222"); exit(1); } fd_set readfds, tempfds; int maxfd, i = 0; FD_ZERO(&readfds); FD_ZERO(&tempfds); //监听init_fd FD_SET(init_fd, &readfds); maxfd = init_fd; tempfds = readfds; while (1) { tempfds = readfds; if (select(maxfd + 1, &tempfds, NULL, NULL, NULL) < 0) { perror("fail to select"); break; } for (i = 0; i < maxfd + 1; i++) { if (FD_ISSET(i, &tempfds)) { //从init_fd中读取结构体 bytes = read(i, buf, BUF_LEN); if (bytes < 0) continue; for (p = buf; p < buf + bytes;) { //转换成inotify_event结构体 even = (struct inotify_event *)p; if (even->mask & IN_CREATE) { if (even->wd == watch_fd_1) printf("create new file: [%s] in %sn", even->name, WATCH_DIR_1); else if (even->wd == watch_fd_2) printf("create new file: [%s] in %sn", even->name, WATCH_DIR_2); } else if (even->mask & IN_DELETE) { if (even->wd == watch_fd_1) printf("delete [%s] from %sn", even->name, WATCH_DIR_1); else if (even->wd == watch_fd_2) printf("delete [%s] from %sn", even->name, WATCH_DIR_2); } else if (even->mask & IN_IGNORED) { if (even->wd == watch_fd_1) printf("%s was deleted!n", WATCH_DIR_1); else if (even->wd == watch_fd_2) printf("%s was deleted!n", WATCH_DIR_2); inotify_rm_watch(init_fd, even->wd); } //p指针向后的偏移 p += sizeof(struct inotify_event) + even->len; } } } } //删除监听的描述符 inotify_rm_watch(init_fd, watch_fd_1); inotify_rm_watch(init_fd, watch_fd_2); close(init_fd); close(watch_fd_1); close(watch_fd_2); return 0; }
|