inotify

转载自:http://blog.csdn.net/longwang155069/article/details/54016789
http://blog.csdn.net/shreck66/article/details/46974155
Inotify是一个Linux特性,它监控文件系统操作,比如读取、写入和创建。Inotify反应灵敏,用法非常简单,并且比cron任务的繁忙轮询高效得多。学习如何将inotify集成到您的应用程序中,并发现一组可用来进一步自动化系统治理的命令行工具。

系统治理就像日常生活一样。就像刷牙和吃蔬菜一样,日常的维护能保持机器的良好状态。您必须定期清空废物,比如临时文件或无用的日志文件,以及花时间填写表单、回复电话、更新和监控进程等。幸好自动化shell脚本、使用Nagios等工具进行监控、通过常见的cron进行任务调度可以减轻这个负担。
但稀奇的是,这些工具没有一个具有响应性。当然,您可以安排一个频繁运行的 cron任务来监控条件,但这样繁忙的轮询 — 消耗大量资源并且具有不确定性 — 并不是很理想。例如,假如您必须监控输入数据的几个
Transfer Protocol(FTP)收存箱,您可能要通过find命令扫描每个目标目录,列举新的内容。然而,尽管这个操作看起来并没有什么害处,但每个调用都产生一个新的 shellfind 命令,这需要许多系统调用来打开目录,然后扫描目录,等等。这会造成过于频繁的或大量的轮询任务(更糟糕的是,繁忙的轮询并不总是很好。想象一下一个文件系统浏览器,比如 Mac OS XFinder,轮询更新时需要的大量资源及其复杂性)。
Inotify 是一个Linux 内核特性,它监控文件系统,并且及时向专门的应用程序发出相关的事件警告,比如删除、读、写和卸载操作等。您还可以跟踪活动的源头和目标等细节。
使用 inotify 很简单:创建一个文件描述符,附加一个或多个监视器(一个监视器 是一个路径和一组事件),然后使用read 方法从描述符获取事件。read并不会用光整个周期,它在事件发生之前是被阻塞的。
更好的是,因为inotify 通过传统的文件描述符工作,您可以利用传统的 select 系统调用来被动地监控监视器和许多其他输入源。两种方法 — 阻塞文件描述符和使用 select— 都避免了繁忙轮询。

1.概述
1)inotify机制可用于监控文件或目录。当监控目录时,与该目录自身以及该目录下面的文件都会被监控,其上有事件发生时都会通知给应用程序

2)inotify监控机制为非递归,若应用程序有意监控整个目录子树内的事件,则需对该树中的每个目录发起inotify_add_watch()调用

3)可使用select(),poll(),epoll()以及由信号驱动的I/O来监控inotify文件描述符

2.inotify API
1)inotify_init()系统调用可创建一新的inotify实例

#include<sys/inotify.h>  
int inotify_init(void);

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

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

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

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

参数mask为一位掩码,针对pathname定义了想要监控的事件,此函数的返回值为一个用于唯一指代此监控项的描述符
3)inotify_rm_watch(int fd, int wd)用于从watch list中移除检测的对象。

3.inotify事件

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不为目录时会失败

1)当文件的元数据(比如,权限,所有权,链接计数,扩展属性,用户ID,或组ID等)改变时,会发生IN_ATTRIB事件

2)删除受监控对象时会发生IN_DELETE_SELF

3)重命名对象时会发生IN_MORE_SELF事件

4)ONE_SHOT允许只监控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: 就是检测的对象的watch descriptor

.mask: 检测事件的mask

.cookie: 和rename事件相关。

.len: name字段的长度。

.name: 检测对象的name

实例:

#include <sys/inotify.h>  
#include <unistd.h>  
#include <string.h>  
#include <stdio.h>  

/* 
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  
}; 

*/  

int watch_inotify_events(int fd)  
{  
    char event_buf[512];  
    int ret;  
    int event_pos = 0;  
    int event_size = 0;  
    struct inotify_event *event;  

    /*读事件是否发生,没有发生就会阻塞*/  
    ret = read(fd, event_buf, sizeof(event_buf));  

    /*如果read的返回值,小于inotify_event大小出现错误*/  
    if(ret < (int)sizeof(struct inotify_event))  
    {  
        printf("counld not get event!\n");  
        return -1;  
    }  

    /*因为read的返回值存在一个或者多个inotify_event对象,需要一个一个取出来处理*/  
    while( ret >= (int)sizeof(struct inotify_event) )  
    {  
        event = (struct inotify_event*)(event_buf + event_pos);  
        if(event->len)  
        {  
            if(event->mask & IN_CREATE)  
            {  
                printf("create file: %s\n",event->name);  
            }  
            else  
            {  
                printf("delete file: %s\n",event->name);  
            }  
        }  

        /*event_size就是一个事件的真正大小*/  
        event_size = sizeof(struct inotify_event) + event->len;  
        ret -= event_size;  
        event_pos += event_size;  
    }  

    return 0;  
}  

int main(int argc, char** argv)  
{  
    int InotifyFd;  
    int ret;  

    if (argc != 2)  
    {  
        printf("Usage: %s <dir>\n", argv[0]);  
        return -1;  
    }  

    /*inotify初始化*/  
    InotifyFd = inotify_init();  
    if( InotifyFd == -1)  
    {  
        printf("inotify_init error!\n");  
        return -1;  
    }  

    /*添加watch对象*/  
    ret = inotify_add_watch(InotifyFd, argv[1], IN_CREATE |  IN_DELETE);  

    /*处理事件*/  
    watch_inotify_events(InotifyFd);  

    /*删除inotify的watch对象*/  
    if ( inotify_rm_watch(InotifyFd, ret) == -1)   
    {  
        printf("notify_rm_watch error!\n");  
        return -1;  
    }  

    /*关闭inotify描述符*/  
    close(InotifyFd);  

    return 0;  
}  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值