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

项目中,要实现用户通过网页设置參数,后台接收数据然后写串口。

网页写数据到本地文件,使用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



posted @ 2017-05-25 14:10  wzzkaifa  阅读(284)  评论(0编辑  收藏  举报