inotify
是 Linux 系统提供的一种文件系统事件监控机制,可以实时监控文件或目录的变化,如创建、删除、修改等操作。使用 inotify
可以帮助开发者构建高效的文件监控应用。下面将详细介绍如何使用 inotify
进行文件监控,包括基本概念、常用 API 以及示例代码。
每个 inotify
实例都有一个唯一的文件描述符,用于管理和监控多个监控事件。
监控对象可以是文件或目录。每个监控对象通过一个 watch
描述,包含监控的路径和相关标志。
当被监控的文件或目录发生指定类型的事件时,inotify
会生成相应的事件通知。
创建一个新的 inotify
实例,返回一个文件描述符。
#include <sys/inotify.h>
int inotify_init(void);
向 inotify
实例添加一个监控对象。
int inotify_add_watch(int fd, const char *path, uint32_t mask);
fd
: inotify_init
返回的文件描述符。path
: 要监控的文件或目录路径。mask
: 监控事件的掩码,如 IN_MODIFY
, IN_CREATE
, IN_DELETE
等。返回值是一个非负的监控描述符,如果出错则返回 -1
。
读取 inotify
事件。
ssize_t read(int fd, void *buf, size_t count);
fd
: inotify
实例的文件描述符。buf
: 用于存储事件的缓冲区。count
: 缓冲区的大小。返回值是读取的字节数,如果到达文件末尾则返回 0
,出错则返回 -1
。
移除一个监控对象。
int inotify_rm_watch(int fd, int wd);
fd
: inotify
实例的文件描述符。wd
: 要移除的监控描述符(由 inotify_add_watch
返回)。返回值 0
表示成功,-1
表示失败。
关闭 inotify
实例。
int close(int fd);
inotify
事件通过 inotify_event
结构体描述,定义如下:
struct inotify_event {
int wd; /* 监控描述符 */
uint32_t mask; /* 事件掩码 */
uint32_t cookie; /* 唯一标识符,用于关联多个事件 */
uint32_t len; /* 文件名长度 */
char name[]; /* 可变长度的文件名 */
};
wd
: 监控描述符,对应 inotify_add_watch
返回的值。mask
: 发生的事件类型,如 IN_MODIFY
, IN_CREATE
, IN_DELETE_SELF
等。cookie
: 事件的唯一标识符,用于关联多个相关事件(如部分读取时)。len
: 文件名的长度(不包括终止的空字符)。name
: 被监控文件或目录的名称。以下是一个使用 inotify
监控目录变化的简单示例:
#include <stdio.h>
#include <stdlib.h>
#include <string.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 length, i = 0;
int fd;
int wd;
char buffer[BUF_LEN];
// 检查参数
if (argc != 2) {
printf("Usage: %s <directory_to_watch>\n", argv[0]);
exit(EXIT_FAILURE);
}
// 创建 inotify 实例
fd = inotify_init();
if (fd < 0) {
perror("inotify_init");
exit(EXIT_FAILURE);
}
// 添加监控
wd = inotify_add_watch(fd, argv[1], IN_MODIFY | IN_CREATE | IN_DELETE);
if (wd < 0) {
perror("inotify_add_watch");
close(fd);
exit(EXIT_FAILURE);
}
printf("Monitoring directory %s for changes...\n", argv[1]);
// 读取事件
while (1) {
length = read(fd, buffer, BUF_LEN);
if (length < 0) {
perror("read");
break;
}
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("Directory %s created.\n", event->name);
} else {
printf("File %s created.\n", event->name);
}
}
if (event->mask & IN_DELETE) {
if (event->mask & IN_ISDIR) {
printf("Directory %s deleted.\n", event->name);
} else {
printf("File %s deleted.\n", event->name);
}
}
if (event->mask & IN_MODIFY) {
if (event->mask & IN_ISDIR) {
printf("Directory %s modified.\n", event->name);
} else {
printf("File %s modified.\n", event->name);
}
}
}
i += EVENT_SIZE + event->len;
}
i = 0;
}
// 移除监控并关闭 inotify 实例
inotify_rm_watch(fd, wd);
close(fd);
exit(EXIT_SUCCESS);
}
保存上述代码为 inotify_example.c
,然后使用以下命令编译:
gcc -o inotify_example inotify_example.c
运行程序并指定要监控的目录:
./inotify_example /path/to/directory
程序将实时监控指定目录的变化,并在检测到创建、删除或修改事件时输出相应的信息。
事件缓冲区大小:inotify
的事件缓冲区有大小限制,默认情况下可能不足以处理大量事件。可以通过调整系统参数或多次读取缓冲区来处理。
事件合并:inotify
可能会合并一些事件,例如连续的写入操作可能被视为一次修改事件。因此,在处理事件时需要注意这一点。
监控深度:inotify
对于监控的文件和目录数量有限制,具体取决于系统配置。可以通过调整 /proc/sys/fs/inotify/max_user_watches
来增加监控数量。
资源管理:确保在程序结束时移除所有监控并关闭 inotify
实例,以释放资源。
跨平台支持:inotify
是 Linux 特有的机制,在其他操作系统上需要使用不同的文件监控机制,如 macOS 的 FSEvents
或 Windows 的 ReadDirectoryChangesW
。
可以通过添加多个 inotify_add_watch
来监控多个文件或目录,或者对同一个监控对象添加不同的事件掩码。
epoll
提高效率对于需要同时处理大量文件描述符的应用,可以结合 epoll
来提高事件处理的效率。
当事件数据超过缓冲区大小时,inotify
会截断事件。可以通过设置 IN_IGNORED
标志并重新添加监控来处理这种情况。
通过以上介绍,相信您已经对如何使用 inotify
进行文件监控有了基本的了解。根据具体需求,可以进一步扩展和优化监控逻辑,以满足实际应用场景。