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

本文涉及的产品
Serverless 应用引擎免费试用套餐包,4320000 CU,有效期3个月
云原生网关 MSE Higress,422元/月
MSE Nacos/ZooKeeper 企业版试用,1600元额度,限量50份
简介: `inotify`是Linux内核提供的文件系统监控机制,用于实时捕获文件和目录的创建、删除、移动和修改等事件。通过`inotify_init`初始化,`inotify_add_watch`添加监视点,如`. IN_ACCESS`, `. IN_MODIFY`等,及`inotify_rm_watch`移除监视。示例代码展示了监听指定路径下文件修改事件,当事件发生时打印信息。使用`inotify`能高效地构建实时应用,如文件同步和日志监控,简化系统编程。

【实战技巧】使用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 阻塞模式的使用示例,阻塞等待事件触发,并及时处理。

    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事件,由于是阻塞模式,不会导致空转。

    int main() {
      InotifyManager inotifyManager;
    
      // 监听当前目录下的文件创建和删除事件
      inotifyManager.AddWatch(".", IN_CREATE | IN_DELETE);
    
      while (true) {
          // 等待并处理事件
          inotifyManager.WaitForEvents();
      }
    
      return 0;
    }
    

效果验证

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

总结

  • 从使用流程来看,inotify用起来比较简单,只需要初始化、添加事件和读取事件即可。
  • inotify 句柄也可以通过 I/O 多路复用(如 epoll/select/poll)进行监听,实现事件的及时响应。
  • inotify 使用场景也比较多,例如界面实时刷新显示文件;监听配置文件变更动态加载配置;作为调试手段,模拟外部事件触发内部响应以及记录一些敏感文件的修改记录等等。
  • 了解这种原生接口,以后如果有需求,能够让实现多一种方式,同时减少开发中的复杂性和时间成本,或许也能够少走一些“弯路”。
相关文章
|
监控 关系型数据库 Linux
|
存储 监控 Linux
【Linux IO多路复用 】 Linux下select函数全解析:驾驭I-O复用的高效之道
【Linux IO多路复用 】 Linux下select函数全解析:驾驭I-O复用的高效之道
2526 0
Jira-API的详细使用例子
下面是Jira-API的详细使用的例子,包含: • Jira的登陆,通过jql批量查询jira-issue, • 获得jira-project下的所有issue,assignee的详细信息, • 添加和更新defect • 下载和上传附件 • 通过Jira登录的cookies搭配requsts库发送自定义的一些http请求
2725 1
|
12月前
|
机器学习/深度学习 人工智能 自然语言处理
AI技术深度解析:从基础到应用的全面介绍
人工智能(AI)技术的迅猛发展,正在深刻改变着我们的生活和工作方式。从自然语言处理(NLP)到机器学习,从神经网络到大型语言模型(LLM),AI技术的每一次进步都带来了前所未有的机遇和挑战。本文将从背景、历史、业务场景、Python代码示例、流程图以及如何上手等多个方面,对AI技术中的关键组件进行深度解析,为读者呈现一个全面而深入的AI技术世界。
1593 10
|
Linux Docker 容器
Docker 的/var/lib/docker/overlay2 占用很大,清理Docker占用的磁盘空间,迁移 /var/lib/docker 目录
Docker 的/var/lib/docker/overlay2 占用很大,清理Docker占用的磁盘空间,迁移 /var/lib/docker 目录
2394 1
|
12月前
|
存储 编译器 Linux
动态链接的魔法:Linux下动态链接库机制探讨
本文将深入探讨Linux系统中的动态链接库机制,这其中包括但不限于全局符号介入、延迟绑定以及地址无关代码等内容。
2062 141
|
API
【Qt 学习笔记】QWidget的toolTip属性 | focusPolicy属性
【Qt 学习笔记】QWidget的toolTip属性 | focusPolicy属性
930 5
|
12月前
|
Kubernetes 应用服务中间件 nginx
二进制安装Kubernetes(k8s)v1.32.0
本指南提供了一个详细的步骤,用于在Linux系统上通过二进制文件安装Kubernetes(k8s)v1.32.0,支持IPv4+IPv6双栈。具体步骤包括环境准备、系统配置、组件安装和配置等。
4054 11
|
Ubuntu Linux Windows
linux 挂载硬盘报错 "mount: unknown filesystem type 'ntfs'"
【10月更文挑战第7天】在Linux系统中挂载硬盘时遇到“mount: unknown filesystem type &#39;ntfs&#39;”错误,是因为Linux默认可能不支持NTFS文件系统。本文提供了解决方案:安装NTFS-3G软件包以支持NTFS,并检查内核是否已加载NTFS模块。对于Ubuntu/Debian系统,可使用`sudo apt-get install ntfs-3g`命令;对于CentOS/RHEL系统,则需先安装EPEL仓库再安装NTFS-3G。此外,还需确认硬盘设备名正确无误,并创建合适的挂载点目录。
2994 2
|
存储 数据安全/隐私保护 Docker
Kolla-ansible部署openStack
Kolla-ansible部署openStack
1717 11

热门文章

最新文章