前往小程序,Get更优阅读体验!
立即前往
发布
社区首页 >专栏 >【实战技巧】使用inotify实现实时文件监控

【实战技巧】使用inotify实现实时文件监控

作者头像
开源519
发布2025-02-27 10:15:55
发布2025-02-27 10:15:55
16500
代码可运行
举报
文章被收录于专栏:开源519开源519
运行总次数:0
代码可运行

【实战技巧】使用inotify实现实时文件监控

开篇

  之前阅读《Linux系统编程》时,留意到了一个Linux原生接口inotify。它能够监控文件的移动、读取、写入和删除等操作。今天利用空闲时间,简单研究了一下如何使用这个接口,并在这里记录下来,方便将来需要查询和参考。

注:文章不定时更新,喜欢本公众号系列文章,可以星标公众号,避免遗漏干货文章。源码开源,原创不易,觉得分享有用,帮忙点赞!

概述

inotify 是 Linux 内核提供的一种文件系统事件监控机制,允许用户空间程序监视文件或目录的各种操作。   通过注册监听事件,程序可以实时捕获文件的创建、删除、移动和修改等操作,无需轮询,极大地提高了效率和实时性。inotify 提供了一种高效的方式来构建实时文件同步、监控日志变更和自动化任务等应用,是现代 Linux 系统编程中不可或缺的一部分。

基础接口

  • int inotify_init(void) / int inotify_init1(int flags)

原型

int inotify_init(void)

功能

初始化一个新的 inotify 实例,并返回一个新的文件描述符,用于后续的操作。

参数

flags:   IN_CLOEXEC:在执行 execve() 后关闭文件描述符(FD_CLOEXEC)。   IN_NONBLOCK:在新的文件描述符上设置 O_NONBLOCK 文件状态标志。使用这个标志可以避免额外调用 fcntl(2) 来达到同样的效果。

返回值

成功:返回一个新的文件描述符,用于标识 inotify 实例。失败:返回 -1,并设置 errno 来指示错误类型。

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

原型

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

功能

向指定的 inotify 实例中添加一个新的文件或目录的监视,并指定要监视的事件类型。

参数

fd:  inotify_init 返回的文件描述符,标识要添加监视的 inotify 实例。 pathname:要监视的文件或目录的路径名。mask:要监视的事件类型的位掩码,可以是以下之一或多个值的按位或组合:  IN_ACCESS:文件被访问。  IN_MODIFY:文件被修改。  IN_ATTRIB:文件属性被修改。  IN_CLOSE_WRITE:可写文件被关闭。  IN_CLOSE_NOWRITE:不可写文件被关闭等。

返回值

成功:返回一个新的监视描述符,用于标识此次监视。失败:返回 -1,并设置 errno 来指示错误类型。

  • int inotify_rm_watch(int fd, int wd)

原型

int inotify_rm_watch(int fd, int wd)

功能

从 inotify 实例中移除先前添加的监视。

参数

fd:inotify_init 返回的文件描述符,标识要移除监视的 inotify 实例。wd:要移除的监视描述符,即调用 inotify_add_watch 返回的监视描述符。

返回值

成功:返回 0。失败:返回 -1,并设置 errno 来指示错误类型。

源码示例

  • 需求: 实现监听指定路径下文件的修改事件,在事件发生时实时打印。
  • 实现: inotify接口使用起来比较简单,大致分为三个步骤: ① inotify初始化 ② 增加监视对象以及监听类型 ③ 等待事件触发,可以结合I/O复用。

整体流程比较简单,这里简单列举一下事件触发响应和测试流程示例:

  • 事件触发响应流程 简单展示 inotify 阻塞模式的使用示例,阻塞等待事件触发,并及时处理。
代码语言:javascript
代码运行次数:0
复制
int InotifyManager::WaitForEvents() {
    const int bufferSize = 1024; // 根据实际需求调整缓冲区大小
    char buffer[bufferSize];

    ssize_t numRead = read(inotifyFd, buffer, bufferSize);
    if (numRead == -1) {
        if (errno != EAGAIN) {
            std::cerr << "Error reading from inotify: " << strerror(errno) << std::endl;
            return -1;
        }
        return 0;
    }

    // 处理所有事件
    int offset = 0;
    while (offset < numRead) {
        struct inotify_event* event = reinterpret_cast<struct inotify_event*>(&buffer[offset]);
        if (event->len > 0) {
            std::cout << "Inotify event: " << event->name;
            if (event->mask & IN_CREATE)
                std::cout << " created";
            if (event->mask & IN_DELETE)
                std::cout << " deleted";
            std::cout << std::endl;
        }
        offset += sizeof(struct inotify_event) + event->len;
    }

    return 0;
}
  • 测试代码 循环等待inotify事件,由于是阻塞模式,不会导致空转。
代码语言:javascript
代码运行次数:0
复制
int main() {
    InotifyManager inotifyManager;

    // 监听当前目录下的文件创建和删除事件
    inotifyManager.AddWatch(".", IN_CREATE | IN_DELETE);

    while (true) {
        // 等待并处理事件
        inotifyManager.WaitForEvents();
    }

    return 0;
}

效果验证

  • 验证流程: ① 左边窗口执行监听程序。 ② 右边窗口先后执行创建和删除hello文件。
  • 验证效果:   监听程序能够及时打印出对应创建和删除事件。

总结

  • 从使用流程来看,inotify用起来比较简单,只需要初始化、添加事件和读取事件即可。
  • inotify 句柄也可以通过 I/O 多路复用(如 epoll/select/poll)进行监听,实现事件的及时响应。
  • inotify 使用场景也比较多,例如界面实时刷新显示文件;监听配置文件变更动态加载配置;作为调试手段,模拟外部事件触发内部响应以及记录一些敏感文件的修改记录等等。
  • 了解这种原生接口,以后如果有需求,能够让实现多一种方式,同时减少开发中的复杂性和时间成本,或许也能够少走一些“弯路”。

最后

用心感悟,认真记录,写好每一篇文章,分享每一框干货。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2024-06-30,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 开源519 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 【实战技巧】使用inotify实现实时文件监控
    • 开篇
    • 概述
    • 基础接口
    • 源码示例
    • 效果验证
    • 总结
    • 最后
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档