實現對文件的實時監控--使用Inotify方法


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

注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
  © 2014-2022 ITdaan.com 联系我们: