实现对文件的实时监控--使用Inotify方法

这篇博客介绍了Linux系统下如何使用Inotify API来监控文件或目录的更改。Inotify机制可以监控文件和目录的多种事件,包括创建、删除、修改等。文章详细讲解了API的使用、事件类型以及如何通过select()函数读取和处理inotify事件。监控文件目录比直接监控文件更稳定,因为直接监控文件可能因文件被删除和重建而失效。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

linux系统下监控文件更改–Inotify API使用方法

1.简介:
  • 1.inotify机制可用于监控文件或目录。当监控目录时,与该目录自身以及该目录下面的文件都会被监控,其上有事件发生时都会通知给应用程序
  • 2.otify监控机制为非递归,若应用程序有意监控整个目录子树内的事件,则需对该树中的每个目录发起inotify_add_watch()调用
  • 可使用select(),poll(),epoll()以及由信号驱动的I/O来监控inotify文件描述符
    ps:后面结合select()使用。
2.API
#include<sys/inotify.h>  
int inotify_init(void);  

该函数的返回值为一个文件描述符,我们可以简单的理解为该文件描述符所指代的文件中将会保存类似所监控的目录所发生的事件集

#include<sys/inotify.h>  
int inotify_add_watch(int fd,const char *pathname,uint32_t mask); 

针对fd所指的inotify实例的监控列表,系统调用inotify_add_watch()可以追加新的监控项。

参数pathname为想要创建的监控项所对应的文件,特别注意调用该接口必须要对该文件有读权限,该函数只对文件做一次检查,如果在监控时修改了所监控的文件读权限,则不会影响继续监控此文件

参数mask为一位掩码,针对pathname定义了想要监控的事件,此函数的返回值为一个用于唯一指代此监控项的描述符

3.事件
IN_ACCESS               文件被访问
IN_ATTRIB               文件元数据改变
IN_CLOSE_WRITE          关闭为了写入而打开的文件
IN_CREATE               在受监控目录下创建了文件或目录
IN_DELETE               在受监控目录内删除了文件或目录
IN_DELETE_SELF          删除了受监控目录/文件本身
IN_MODIFY               文件被修改
IN_MODIFY_SELF          移动受监控目录或文件本身
IN_MOVED_FROM           文件移除受监控目录
IN_MOVED_TO         将文件移到受监控目录
IN_OPEN                 文件被打开

IN_ALL_EVENTS           以上所有输出事件的统称
IN_MOVE             IN_MOVED_FROM | IN_MOVED_TO事件的统称
IN_ONESHOT              只监控pathname的一个事件
IN_ONLYDIR              pathname不为目录时会失败
4.读取inotify事件

将监控项项在监控列表中登记后,应运程序可用read()从inotify的文件描述符中读取事件,以判定发生了那些事件。若读取之时还没有发生任何事件,则read()会阻塞,直至有事件产生,事件发生后,每次调用read()会返回一个缓存区,内含一个或多个如下类型的结构体:

struct inotify_event {  
            int      wd;       /* Watch descriptor */  
            uint32_t mask;     /* Mask of events */  
            uint32_t cookie;   /* Unique cookie associating related 
                                  events (for rename(2)) */  
            uint32_t len;      /* Size of ’name’ field */  
            char     name[];   /* Optional null-terminated name */  
        };  

字段wd指名发生事件的是哪个监控描述符,该字段值由之前对inotify_add_watch()的调用返回。因为用read()读到的是inotify文件中的所有事件,可是当inotify同时监控多个目录或文件时我们应该如何区分读到的内容呢,这是wd就派上了用场,我们可以用wd来做区分

.mask字段返回了描述该事件的位掩码
.cookie字段将相关事件联系到一起,目前只有对重命名时才会用到
.len字段表示实际分配给name字段的字节数
.name字段则是标示该文件.

ps:最好将监控的文档放入文件夹内,监控文件目录。如直接监控文件,文件内容如果更改(一般使用文本编辑器改变文件,编辑器首先删除文件,再创建。造成原来我们注册的文件描述符实效)则会返回IN_DELETE_SELF删除了受监控目录 造成无inotifyFd无效.

使用select接收更改事件:

源码:

#include<stdio.h>
#include<assert.h>
#include<unistd.h>
#include<stdlib.h>
#include<errno.h>
#include<string.h>
#include<sys/types.h>
#include<sys/inotify.h>
#include<limits.h>
#include<fcntl.h>
#include<sys/ioctl.h>
#include<sys/time.h>

#define BUF_LEN 1000

void display(struct inotify_event *i, char ** argv)
{
    printf("wd = %2d;", i->wd);

    if(i -> cookie > 0)
    {
        printf("cookie = %4d;",i->cookie);
    }

    printf("mask = ");
 //    if(i ->mask & IN_ACCESS) printf("IN_ACCESS\n");
 //    if(i ->mask & IN_DELETE_SELF) printf("IN_DELETE_SELF\n");
       if(i ->mask & IN_MODIFY) printf("IN_MODIFY\n");
  //   if(i ->mask & IN_OPEN) printf("IN_OPEN\n"); 
       if((i ->mask & IN_MODIFY)&&(i ->wd == 1))  //判断是那个文件进行了更改
    {
        printf("IN_ATTRIB %s Changed\n",argv[1]);
    }else{
        printf("IN_ATTRIB %s Changed\n",argv[2]);
    }

    if(i -> len > 0)
    {
        printf("name = %s\n",i->name);
    }
}

int
main(int argc,char **argv)
{
    int inotifyFd, wd, wd2, j;
    char buf[BUF_LEN];
    char *p;
    struct inotify_event *event;
    int flages;

    ssize_t numRead;
    fd_set inputs, testfds;
    struct timeval timeout;
    int result;

    if(argc < 2)
    {
        printf("error\n");
    }

    inotifyFd = inotify_init(); //系统调用可创建一新的inotify实例  初始化实例
    if(inotifyFd == -1)
    {
        printf("init error\n");
        return 0;
    }

    wd = inotify_add_watch(inotifyFd,argv[1],IN_MODIFY);  //系统调用inotify_add_watch()可以追加新的监控项
    if(wd == -1)
    {
        printf("error wd\n");
    }
    wd2 = inotify_add_watch(inotifyFd,argv[2],IN_MODIFY);
    if(wd2 == -1)
    {
        printf("error wd2\n");
    }
    printf("watching %s using wd =  %d\n", argv[1],wd);
    printf("watching %s using wd =  %d\n", argv[2],wd2);
    FD_ZERO(&inputs);
    FD_SET(inotifyFd,&inputs);  //将inotify的文件秒速符加入到 select中

    while(1)  //开启非阻塞select模式  
    {
        int fd;
        testfds = inputs;
        result = select(FD_SETSIZE, &testfds, (fd_set *)0, (fd_set *)0, (struct timeval *) 0);
        if (result < 1)
        {
            perror("server err");
        }
        for(fd = 0; fd < FD_SETSIZE; fd++)
        {
            if(FD_ISSET(fd, &testfds))   //收到消息 处理消息
            {
                if(fd == inotifyFd)
                {
                            numRead = read(inotifyFd,buf,BUF_LEN);
                             if(numRead == -1)
                            {
                                printf("read error\n");
                              }

                             printf("read %ld bytes from inotify fd\n",(long)numRead);
                             for(p = buf; p < buf+numRead;)
                             {
                               event = (struct inotify_event *)p;
                              display(event,argv);
                              p+=sizeof(struct inotify_event)+ event->len;
                             }//for
                   }//if()
            }//if(fd)
        }//for()
    }//while(1)
    close(inotifyFd);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值