inotify 文件监控机制

发布于:2025-05-11 ⋅ 阅读:(10) ⋅ 点赞:(0)

        inotify 是 Linux 内核提供的一种高效文件系统事件监控机制,允许应用程序实时监控文件或目录的变化(如创建、修改、删除等),而无需轮询(polling)。当监控一个目录时,inotify 会返回该目录本身及其内部文件的事件。

函数介绍

int inotify_init(void);
int inotify_init1(int flags);//较新的API

描述:

        用于创建一个 inotify 实例,并返回一个引用该实例的文件描述符。如果 flags 参数为 0,则 inotify_init1() 的行为与 inotify_init() 完全相同。

参数:

        flags值如下(可以按位或组合):

                IN_NONBLOCK:非阻塞

                IN_CLOEXEC: 设置执行时关闭close-on-exec (FD_CLOEXEC)标志;指定此标志可避免程序额外调用 fcntl的 F_SETFD 操作来设置 FD_CLOEXEC 标志。

返回值:

        inotify 实例的文件描述符

int inotify_add_watch(int fd, const char *pathname, uint32_t mask);

描述:

        指定路径(pathname)的文件或目录添加一个新的监视项(watch),或修改一个已存在的监视项。调用此函数的进程必须对该文件具有读权限。

参数:

        fd : inotify_init返回的文件描述符

        pathname:要添加的文件或目录路径

        mask:掩码,指定要监视的事件类型

        mask取值(按位或):


IN_ACCESS //文件被读取(如 read()、execve())。
IN_MODIFY //文件内容被修改(如 write()、truncate())。
IN_OPEN //文件被打开。
IN_CLOSE_WRITE //以写入方式打开的文件被关闭。
IN_CLOSE_NOWRITE //以非写入方式打开的文件被关闭。
IN_ATTRIB //文件元数据被修改(如权限、时间戳、扩展属性、链接数、UID、GID 等)。
IN_CREATE //在监视的目录中创建文件或目录。
IN_DELETE //从监视的目录中删除文件或目录。
IN_DELETE_SELF //被监视的文件或目录本身被删除。
IN_MOVED_FROM //文件被移出被监视的目录。
IN_MOVED_TO //文件被移入被监视的目录。
IN_MOVE_SELF //被监视的文件或目录本身被移动或重命名。
IN_ONLYDIR //仅当 pathname 是目录时才允许监视。
IN_DONT_FOLLOW //不跟随符号链接(如果 pathname 是符号链接,则不解析其指向的目标)。
IN_EXCL_UNLINK //不为已取消链接的文件生成事件(避免监视已被删除但仍有进程引用的文件)。
IN_MASK_ADD //如果监视项已存在,则将新事件添加到现有掩码中,而不是替换原有掩码。
IN_ONESHOT //只监视一次事件,事件发生后自动移除监视。
IN_ALL_EVENTS //监视所有事件(通常为上述事件的按位或组合)。
IN_MOVE //等价于 IN_MOVED_FROM | IN_MOVED_TO。
IN_CLOSE //等价于 IN_CLOSE_WRITE | IN_CLOSE_NOWRITE。

返回值:

        监视描述符(可能新分配或复用已有描述符);

        监视的 文件系统对象(文件或目录)未被当前 fd 关联的 inotify 实例监视过 时,内核会为其分配一个新的 wd。

        监视的 文件系统对象已被当前 fd 关联的 inotify 实例监视过 时,内核会复用已存在的 wd,而非分配新值。

        示例代码:

int fd = inotify_init(); // 初始化 inotify 实例
int wd = inotify_add_watch(fd, "/home/user/docs", IN_CREATE); // 添加监视项
if (wd == -1) {
    perror("inotify_add_watch");
    exit(EXIT_FAILURE);
}

        fd:inotify 实例的全局标识符,整个 inotify 实例(可管理多个监视项)

        wd:监视项的局部标识符,单个监视项(如某个文件或目录)

int inotify_rm_watch(int fd, int wd);

描述:

        从与文件描述符 fd 关联的 inotify 实例中移除与监视描述符 wd 对应的监视项。

参数:

        fd:inotify 实例

        wd:监视项

返回值:

        成功:0

        失败:-1,并且设置errno变量,通过perror获取

信息结构

        事件触发后发送的消息格式:struct inotify_event:

#include <sys/inotify.h>

struct inotify_event {
    int      wd;         // 监视描述符(标识哪个监视项触发事件)
    uint32_t mask;      // 事件掩码(标识触发的事件类型)
    uint32_t cookie;    // 用于关联事件的唯一标识(通常用于重命名事件)
    uint32_t len;       // 事件附带数据的长度(如文件名长度)
    char     name[];    // 可选:文件名(仅当事件涉及目录内文件时存在)
};

事件触发

可以通过两种方法来处理事件触发:

1.使用select/epoll等来监视内核通知(监视inotify_init返回的文件描述符fd);

2.使用read接口主动读取(读取inotify_init返回的文件描述符fd));

示例代码(read为例):

char buffer[4096];
ssize_t len;

while (1) {
    len = read(fd, buffer, sizeof(buffer));
    if (len == -1) {
        perror("read");
        break;
    }

    // 解析事件
    struct inotify_event *event = (struct inotify_event *)buffer;
    while ((char *)event < buffer + len) {
        if (event->mask & IN_MODIFY) {
            printf("File modified. WD=%d, Path=%s\n", event->wd, event->name);
        }
        if (event->mask & IN_DELETE) {
            printf("File deleted. WD=%d, Path=%s\n", event->wd, event->name);
        }
    }
}


网站公告

今日签到

点亮在社区的每一天
去签到