Linux-Inotify

名称

inotify - 监视文件系统事件

描述

  1. Inotify可用于监视单个文件或监视目录
  2. 监视目录时,inotify将返回目录本身以及目录内文件的事件。
  3. 目录的Inotify监视不是递归的:要监视目录下的子目录,必须创建其他监视。
  4. inotify API不提供有关触发inotify事件的用户或进程的信息。
  5. 通过从inotify文件描述符读取返回的事件形成有序队列。
  6. 可以使用select(2),poll(2)和epoll(7)监视Inotify文件描述符。当事件可用时,文件描述符表示可读。
  7. 如果在inotify文件描述符上生成的连续输出inotify事件是相同的(相同的wd,掩码,cookie和名称),那么如果尚未读取旧事件,则它们将合并为单个事件(但请参阅BUGS)。

API

#include <sys/inotify.h>
inotify_init()
inotify_add_watch()
inotify_rm_watch()
  • int inotify_init(void)
    初始化一个新的inotify实例,返回与新的inotify事件队列关联的文件描述符。

返回值:
成功时,这些系统调用返回一个新的文件描述符。
出错时,返回-1,并设置errno 以指示错误

错误码含义
EINVAL(inotify_init1())在flags中指定了无效值。
**EMFILE **已达到用户对inotify实例总数的限制。
ENFILE已达到系统对文件描述符总数的限制。
ENOMEM内核内存不足。
  • int inotify_add_watch(int fd, const char *pathname, uint32_t mask);
    将wathc添加到初始化的inotify实例;为路径名中指定位置的文件添加新监视或修改现有监视;

fd::参数是文件描述符指的是inotify实例,其观察名单将被修改。
pathname: 被监视文件的或目录的路径,调用者必须具有此文件的读取权限。
mask:要监视路径名的事件在mask bit-mask参数中指定。
返回值
成功时,inotify_add_watch()返回非负监视描述符。
错误时,返回-1,并正确设置errno。

错误码含义
EACCES不允许对给定文件进行读访问。
EBADF给定的文件描述符无效。
EFAULTpathname指向进程可访问的地址空间之外。
EINVAL给定的事件掩码不包含有效事件; 或fd不是inotify文件描述符。
ENOENT路径名中的目录组件不存在或是悬挂的符号链接。
ENOMEM内核内存不足。
ENOSPC达到了用户对inotify监视总数的限制,或者内核无法分配所需的资源
  • int inotify_rm_watch(int fd, int wd);
    从与文件描述符fd关联的inotify实例中删除与监视描述符wd关联的监视。

fd:inotify_init() 返回的inotify 实例
wd:inotify_add_watch()返回的监视描述符

返回值
成功时,inotify_rm_watch()返回零,
错误时,返回-1(在这种情况下,正确 设置errno)。

错误码含义
EBADFfd不是有效的文件描述符。
EINVAL监视描述符wd无效; 或fd不是inotify文件描述符。

数据结构

事件发生后,read函数返回一个包含一个或多个以下结构的buffer

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()返回的监视描述符
mask:包含发生事件的bit位
cookie:是连接相关事件的唯一整数。目前,这仅用于重命名事件,并允许应用程序连接生成的 IN_MOVED_FROM和IN_MOVED_TO事件对。对于所有其他事件类型,cookie设置为0。
len: name数组的长度
name: 发生事件的文件名的路径,每个路径以空格分割。

inotify event

可监视事件:

IN_ACCESS          以读方式访问文件
IN_ATTRIB         文件属性改变  举例: 权限,时间戳,扩展名,链接数,属主,属组的修改 
IN_CLOSE_WRITE    关闭以写方式打开的文件
IN_CLOSE_NOWRITE  未写入的文件已关闭
IN_CREATE         在监视目录中创建文件或文件夹
IN_DELETE         在监视目录中删除文件或文件夹
IN_DELETE_SELF    被监视的文件/目录本身已被删除。
IN_MODIFY         文件已经修改
IN_MOVE_SELF      被监视的文件/目录本身已被移动。
IN_MOVED_FROM     文件移出监视目录
IN_MOVED_TO       文件移入监视目录
IN_OPEN           打开文件
IN_MOVE           等于IN_MOVED_FROM  | IN_MOVED_TO
IN_CLOSE          等于IN_CLOSE_WRITE |  IN_CLOSE_NOWRITE

内核限制

以下接口可用于限制inotify消耗的内核内存量:
/proc/SYS/FS/inotifyd/max_queued_events
inotify实例数上限,超出此限制的事件将被删除,但始终会生成IN_Q_OVERFLOW事件。

/proc/SYS/FS/inotifyd/max_user_instances
每个用户可以创建的inotify实例数的上限。

/proc/SYS/FS/inotifyd/max_user_watches
这指定了可以为每个真实用户创建的监视数量的上限。

编码

#include<stdio.h>
#include<stdlib.h>
#include<sys/inotify.h>
#define BUF_LEN 1000
void dealwithEvent(int fd_instan)
{
	int readlen;
	char buf[BUF_LEN] ={0};
	char * p;
	struct intofiy_event * event;
	//读取事件,返回多个event结构体
	readlen = read(fd_instan,buf, BUF_LEN);
	if ( -1 == readlen )
	{
		printf("read failed errmsg = %s\n", strerror(errno));
		exit(0);
	}
	for ( p =buf; p < buf+readlen;)
	{
			event = (struct inotify_event *)p;
			if( event->mask & IN_CREATE)
			{
				printf("创建文件,filename = %s\n",event->name);
			}
			if( event->mask & IN_DELETE)
			{
				printf("删除文件,filename = %s\n",event->name);
			}
			p += sizeof(struct inotify_event) + event->len;
	}	
}

void do_select(int fd)
{
	int ret;
	fd_set rset;
	struct timeval timeout;
	while(1)
	{
		FD_ZERO(&rset);//每次循环背后,都需要重置
		FD_SET(fd, &rset);
		timeout.tv_sec = 5; //每次select后,都需要重置时间
		timeout.tv_usec = 0;
		
		//利用select 通知时间的发生
		ret  = select(fd+1, &rset,NULL,NULL,&timeout);
		if( 0== ret)
		{
			printf(" Select timeout,continue\n");
			continue;
		}
		else if(-1 == ret)
		{
			printf("select error,break\n");
			break;
		}
		else
		{
			// fd可读
			if (FD_ISSET(fd, &rset))
			{
				dealwithEvent(fd);
			}
		}
	}
}

int main()
{
	int fd_instan;
	int wd;
	fd_instan  = inotify_init();
	if ( -1 == fd_instan)
	{
		printf("init error\n");
		return -1;
	}
	//添加监视点
	wd = inotify_add_watch(fd, "/home/lxj/work/", IN_CREATE|IN_DELETE|IN_CLOSE_WRITE);
	if (-1 == wd)
	{
		printf("inotify_add_watch error \n");
		return -1;
		close(fd_instan);
	}
	//利用select执行IO复用
	do_select(fd_instal);
	
	//删除监视,关闭inotify实例
	inotify_rm_watch(fd_instan,wd);
	close(fd_instan);
	return 1;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值