您的位置:首页 > 运维架构 > Linux

Linux下使用inotify实现对文件的监控

2015-08-19 13:21 721 查看
项目中,要实现用户通过网页设置参数,后台接收数据然后写串口。

网页写数据到本地文件,使用inotify监控文件的IN_MODIFY事件,当文件被修改,然后触发写串口事件。

第一个程序仅仅把要监控的文件加入watch_list中,执行程序,发现select返回,只能检测到文件被修改,

但是如果同时监控多个文件,却不能区分是哪个文件被改动了。

/*This is the sample program to notify us for the file creation and file deletion takes place in “/tmp” directory*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <linux/inotify.h>

#define FILE1 "request"
#define FILE2 "time"
#define EVENT_SIZE  ( sizeof (struct inotify_event) )
#define EVENT_BUF_LEN     ( 1024 * ( EVENT_SIZE + 16 ) )

int main( )
{
int length,i=0;
int fd,maxfd;
int wd1;
int wd2;
int ret;
fd_set rfds;
fd_set wfds;
struct timeval tv;
char buffer[EVENT_BUF_LEN];

/*creating the INOTIFY instance*/
fd = inotify_init();

/*checking for error*/
if ( fd < 0 )
{
perror( "inotify_init" );
exit(-1);
}

/*adding the “/tmp” directory into watch list. Here, the suggestion is to validate the existence of the directory before adding into monitoring list.*/
wd1 = inotify_add_watch( fd,FILE1, IN_MODIFY);
if(wd1 < 0)
{
perror("inotify_add_watch");
exit(-1);
}

wd2 = inotify_add_watch( fd,FILE2, IN_MODIFY);
if(wd2 < 0)
{
perror("inotify_add_watch");
exit(-1);
}
/*read to determine the event change happens on “/tmp” directory. Actually this read blocks until the change event occurs*/

while(1)
{
printf("begining while\n");
FD_ZERO(&rfds);
FD_SET(fd,&rfds);
maxfd = fd + 1;
tv.tv_sec = 10;
tv.tv_usec = 0;

printf("waiting select ...\n");
ret = select(maxfd,&rfds,NULL,NULL,&tv);
switch(ret)
{
case -1:
fprintf(stderr,"select failed\n");
break;
case 0:
fprintf(stderr,"select timeout...\n");
continue;
default:
fprintf(stderr,"fd is readable.\n");
length = read(fd,buffer,EVENT_BUF_LEN);
printf("length=%d\n",length);
if(length < 0)
{
perror("read");
exit(-1);
}
while(i < length)
{
fprintf(stderr,"inside while ...\n");
struct inotify_event *event = (struct inotify_event*)&buffer[i];
printf("event->len = %d\n",event->len);
if(event->len)
{
if(event->mask & IN_MODIFY)
{
printf("detected file %s modified.\n",event->name);
}
}
i += EVENT_SIZE + event->len;
}
i = 0;
inotify_rm_watch(fd,wd1);
inotify_rm_watch(fd,wd2);
close(fd);
fd = inotify_init();
wd1 = inotify_add_watch( fd,FILE1, IN_MODIFY);
wd2 = inotify_add_watch( fd,FILE2, IN_MODIFY);
break;
/*
printf("detected file modified\n");
sleep(1);
inotify_rm_watch(fd,wd);
close(fd);
fd = inotify_init();
wd = inotify_add_watch( fd,TEST_FILE, IN_MODIFY);
break;
*/
}
printf("break switch\n");

}
inotify_rm_watch(fd,wd1);
inotify_rm_watch(fd,wd2);
close(fd);

return 0;
}


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 identifies the watch for which this event occurs. It is one of the watch descriptors returned by a previous call to inotify_add_watch(2).

mask contains bits that describe the event that occurred (see below).

cookie is a unique integer that connects related events. Currently this is only used for rename events, and allows the resulting pair of IN_MOVE_FROM

and IN_MOVE_TO events to be connected by the application.

The name field is only present when an event is returned for a file inside a watched directory; it identifies the file pathname relative to the watched

directory. This pathname is null-terminated, and may include further null bytes to align subsequent reads to a suitable address boundary.

The len field counts all of the bytes in name, including the null bytes; the length of each inotify_event structure is thus sizeof(inotify_event)+len.

The behavior when the buffer given to read(2) is too small to return information about the next event depends on the kernel version: in kernels before

2.6.21, read(2) returns 0; since kernel 2.6.21, read(2) fails with the error EINVAL.

又仔细阅读了man inotify,发现只有把目录添加到watch_list,才能获得是目录中的哪一个文件被修改了。

/*This is the sample program to notify us for the file creation and file deletion takes place in “/tmp” directory*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <linux/inotify.h>

#define MONITOR_PATH "/home/lucifer/working/2015_08_19"
#define EVENT_SIZE  ( sizeof (struct inotify_event) )
#define EVENT_BUF_LEN     ( 1024 * ( EVENT_SIZE + 16 ) )

int main( )
{
int length,i=0;
int fd,maxfd;
int wd1;
int ret;
fd_set rfds;
fd_set wfds;
struct timeval tv;
char buffer[EVENT_BUF_LEN];

/*creating the INOTIFY instance*/
fd = inotify_init();

/*checking for error*/
if ( fd < 0 )
{
perror( "inotify_init" );
exit(-1);
}

/*adding the “/tmp” directory into watch list. Here, the suggestion is to validate the existence of the directory before adding into monitoring list.*/
wd1 = inotify_add_watch( fd,MONITOR_PATH, IN_MODIFY);
if(wd1 < 0)
{
perror("inotify_add_watch");
exit(-1);
}

/*read to determine the event change happens on “/tmp” directory. Actually this read blocks until the change event occurs*/

while(1)
{
printf("begining while\n");
FD_ZERO(&rfds);
FD_SET(fd,&rfds);
maxfd = fd + 1;
tv.tv_sec = 10;
tv.tv_usec = 0;

printf("waiting select ...\n");
ret = select(maxfd,&rfds,NULL,NULL,&tv);
switch(ret)
{
case -1:
fprintf(stderr,"select failed\n");
break;
case 0:
fprintf(stderr,"select timeout...\n");
continue;
default:
fprintf(stderr,"fd is readable.\n");
length = read(fd,buffer,EVENT_BUF_LEN);
printf("length=%d\n",length);
if(length < 0)
{
perror("read");
exit(-1);
}
while(i < length)
{
fprintf(stderr,"inside while ...\n");
struct inotify_event *event = (struct inotify_event*)&buffer[i];
printf("event->len = %d\n",event->len);
if(event->len)
{
if(event->mask & IN_MODIFY)
{
printf("detected file %s modified.\n",event->name);
}
}
i += EVENT_SIZE + event->len;
}
i = 0;
inotify_rm_watch(fd,wd1);
close(fd);
fd = inotify_init();
wd1 = inotify_add_watch( fd,MONITOR_PATH, IN_MODIFY);
break;
/*
printf("detected file modified\n");
sleep(1);
inotify_rm_watch(fd,wd);
close(fd);
fd = inotify_init();
wd = inotify_add_watch( fd,TEST_FILE, IN_MODIFY);
break;
*/
}
printf("break switch\n");

}
inotify_rm_watch(fd,wd1);
close(fd);

return 0;
}


caution:当检测文件的IN_MODIFY事件的时候,会发现IN_MODIFY会触发多次

下面是原因

Q: What is the difference between IN_MODIFY and IN_CLOSE_WRITE?

The IN_MODIFY event is emitted on a file content change (e.g. via the write() syscall) while IN_CLOSE_WRITEoccurs on closing the changed file. It means each change operation causes one IN_MODIFY event (it may occurmany times during manipulations with an open
file) whereas IN_CLOSE_WRITE is emitted only once (on closingthe file).

引用地址:http://inotify.aiken.cz/?section=inotify&page=faq
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: