简述
Linux inotify
是一种监控文件系统中文件和目录变化的机制,能够实时地监视文件和目录的变化并通知相应的进程。
在Linux
系统中,文件系统的访问和管理是通过系统调用进行的。inotify
机制是基于这些系统调用实现的,主要是通过inotify_init
创建一个inotify
实例,并使用inotify_add_watch
注册需要监控的文件或目录。一旦文件或目录发生变化,例如文件被创建、修改、删除、重命名等操作,inotify
机制就会通知相应的进程。
通过inotify
机制,可以轻松地监控文件系统中的变化,例如:
当一个文件被创建时,通知相应的进程进行处理。
当一个目录被修改时,通知相应的进程重新加载目录中的文件。
当一个文件被删除时,通知相应的进程进行清理操作等。inotify
机制在许多常见的应用程序中都得到了广泛的应用,例如监控日志文件、文件同步等。它的优点在于可以实时地获取文件系统的变化,而不需要使用轮询等方式浪费系统资源。
方法详解
-
int inotify_init(void)
:创建一个inotify
实例并返回其文件描述符。该函数不需要参数,返回一个非负整数,如果失败则返回-1。 -
int inotify_add_watch(int fd, const char *pathname, uint32_t mask)
:将pathname
指定的文件或目录加入到inotify
实例中进行监控。参数fd
是inotify
实例的文件描述符,pathname
是要监控的文件或目录的路径,mask是要监听的事件类型,包括以下几种事件:
- IN_ACCESS:文件或目录被访问
- 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:文件或目录被打开
可以使用位或运算符将多个事件类型合并起来。该函数返回一个非负整数表示此文件或目录的监控描述符,如果失败则返回-1。
-
int inotify_rm_watch(int fd, int wd)
:停止对指定监控描述符的监控。参数fd
是inotify
实例的文件描述符,wd
是要停止监控的文件或目录的监控描述符。该函数不返回值。 -
ssize_t read(int fd, void *buf, size_t count)
:读取inotify
实例中的事件。参数fd
是inotify
实例的文件描述符,buf
是存放事件的缓冲区,count是缓冲区的大小。该函数返回读取到的字节数,如果返回0表示监控实例中没有新的事件产生,如果返回-1表示读取失败。
在读取到事件后,可以通过以下结构体来解析事件:
cCopy codestruct inotify_event {
int wd; // 监控描述符
uint32_t mask; // 事件类型
uint32_t cookie; // 对于MOVED_FROM和MOVED_TO事件,用cookie来关联事件
uint32_t len; // 文件名的长度
char name[]; // 文件名
};
其中,wd
是事件所对应的监控描述符,mask
是事件类型,cookie
是用于关联MOVED_FROM
和MOVED_TO事件的cookie
,len
是文件名的长度,name
是文件名。
实例
当你想知道一个目录下是否有文件被创建、删除、修改或移动时,可以使用inotify
机制来实现。以下是一个简单的例子:
假设我们有一个目录/tmp
,希望在该目录下监控所有文件的变化。可以使用inotify
机制来监控这个目录,如下所示:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/inotify.h>
#define EVENT_SIZE (sizeof(struct inotify_event))
#define BUF_LEN (1024 * (EVENT_SIZE + 16))
int main(int argc, char **argv) {
int fd, wd, length, i = 0;
char buffer[BUF_LEN];
// 创建inotify实例
fd = inotify_init();
if (fd < 0) {
perror("inotify_init");
exit(EXIT_FAILURE);
}
// 添加监控路径
wd = inotify_add_watch(fd, "/tmp", IN_CREATE | IN_DELETE | IN_MODIFY);
if (wd < 0) {
perror("inotify_add_watch");
exit(EXIT_FAILURE);
}
// 循环读取inotify事件
while (1) {
length = read(fd, buffer, BUF_LEN);
if (length < 0) {
perror("read");
exit(EXIT_FAILURE);
}
// 处理inotify事件
i = 0;
while (i < length) {
struct inotify_event *event = (struct inotify_event *) &buffer[i];
if (event->len) {
if (event->mask & IN_CREATE) {
if (event->mask & IN_ISDIR)
printf("目录 %s 被创建了\n", event->name);
else
printf("文件 %s 被创建了\n", event->name);
}
else if (event->mask & IN_DELETE) {
if (event->mask & IN_ISDIR)
printf("目录 %s 被删除了\n", event->name);
else
printf("文件 %s 被删除了\n", event->name);
}
else if (event->mask & IN_MODIFY) {
if (event->mask & IN_ISDIR)
printf("目录 %s 被修改了\n", event->name);
else
printf("文件 %s 被修改了\n", event->name);
}
}
i += EVENT_SIZE + event->len;
}
}
// 关闭inotify实例
inotify_rm_watch(fd, wd);
close(fd);
return 0;
}
上述代码中,我们使用inotify_init()
函数创建了一个inotify
实例,并使用inotify_add_watch()
函数将/tmp
目录添加到监控列表中,监听文件的创建、删除和修改事件。然后进入一个无限循环,使用read()
函数读取inotify
实例中的事件,处理文件变化事件,并输出相应的提示信息。
例如,当在/tmp
目录下新建了一个文件test.txt
,程序会输出:
文件 test.txt 被创建了
类似地,当有文件被删除、修改或移动时,程序也会收到相应的事件通知。这样就可以实时监控文件系统的变化,进行相应的操作。