1. 程式人生 > >inotify檔案監控

inotify檔案監控

轉自http://blog.csdn.NET/hjhcs121/article/details/7477147

inotify是什麼?用它能幹些什麼?

         通俗點說它是一個核心用於通知使用者空間程式檔案系統變化的系統,並且它是powerful yet simple的。

inotify是Linux系統2.6.13以後核心支援的一種特性,功能是監視檔案系統的變化,在監聽到檔案系統變化後會向相應的應用程式傳送事件。典型應用場景比如檔案管理器,理想情況下應該在使用者使用其他手段修改了資料夾的內容後馬上反映出最新的內容,而不應該在使用者手動重新整理後才顯示最新內容。如果沒有類似inotify的機制,一般會採用輪詢的方式實現這種功能,不能在第一時間反映檔案系統變化而且浪費CPU時間。

inotify的使用者介面原型主要有以下3個:
#include  <sys/inotify.h>

初始化:int inotify_init(void);

               int    fd  =  inotify_init();
新增監視物件:int inotify_add_watch(int fd, const char *path, uint32_t mask);

             int   wd   = inotify_add_watch(fd,path,mask);

             fd是inotify_init()的返回值。

             const  char *path是要監控的檔案(目錄)的路徑。

             uint32_t   mask是:

             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,檔案被開啟

             還有非常多的事件可以使用。使用man   inotify可以檢視所有可以監聽的事件。

             mask是上面這些事件的或。例如IN_ACCESS|IN_MODIFY。

             返回值:wd表示對那個檔案進行監控。
刪除監視物件:int inotify_rm_watch(int fd, uint32_t wd);

             引數fd是inotify_init的返回值。

                    wd是inotify_add_watch的返回值。

             inotify_rm_watch刪除對wd所指向的檔案的監控。

讀取監控發生的事件:

             size_t len = read(fd, buf, BUF_LEN);

             讀取事件資料,buf應是一個指向inotify_event結構陣列的指標。不過要注意的是inotify_event的name成員長度是可變的,這個問題後面再解釋。

             注意:其中buf是一個指向struct  inotify_event陣列的指標。

                      由於struct   inotify_event長度是可變的,因此在讀取inotify_event陣列內容的時候需要動態計算一下時間資料的偏移量。index += sizeof(struct inotify_event)+event->len,len即name成員的長度。

其實還是沒有講的很清楚,不過看了下面的例子,一定非常清楚:

#include <stdio.h>   
#include <unistd.h>   
#include <sys/select.h>   
#include <errno.h>   
#include <sys/inotify.h>   
  
static void   _inotify_event_handler(struct inotify_event *event)      //從buf中取出一個事件。  
{   
         printf("event->mask: 0x%08x\n", event->mask);   
         printf("event->name: %s\n", event->name);   
}   
  
int  main(int argc, char **argv)   
{   
  if (argc != 2) {   
    printf("Usage: %s <file/dir>\n", argv[0]);   
    return -1;   
  }   
  
  unsigned char buf[1024] = {0};   
  struct inotify_event *event = NULL;              


  int fd = inotify_init();                 //初始化監視器
  int wd = inotify_add_watch(fd, argv[1], IN_ALL_EVENTS);                  //監控指定檔案的ALL_EVENTS。
  
  for (;;) 

  {   
       fd_set fds;   
       FD_ZERO(&fds);                
       FD_SET(fd, &fds);   


       if (select(fd + 1, &fds, NULL, NULL, NULL) > 0)                //監控fd的事件。當有事件發生時,返回值>0

       {   
           int len, index = 0;   
           while (((len = read(fd, &buf, sizeof(buf))) < 0) && (errno == EINTR));      //沒有讀取到事件。
           while (index < len) 

           {   
                  event = (struct inotify_event *)(buf + index);                      
                  _inotify_event_handler(event);                                             //獲取事件。
                  index += sizeof(struct inotify_event) + event->len;             //移動index指向下一個事件
           }   
       }   
  }   
  
  inotify_rm_watch(fd, wd);              //刪除對指定檔案的監控。
  
  return 0;   
}  
22222222222-------------------------------------------------------------------------------------------------------------------------------

    Linux下使用inotify監控檔案動作
    發表於 2011年07月01日 | 分類: 1 基礎C/C++archlinux | 發表評論 在日常應用中,常常會遇到以下場景,監控資料夾A,若資料夾中的B檔案發生變化,則執行C命令。Linux下可以通過inotify完成該功能。
自從Linux kernel 2.6.13起,inotify以作為核心的一部份,同時需要glibc 2.4以上版本。

1. 相關函式

inotify_init() - 建立一個inotify例項
inotify_add_watch(int fd, const char *pathname, uint32_t mask) - 加入檔案或目錄到inotify進行監測
inotify_rm_watch(int fd, int wd) - 移除一個watcher

2. 相關結構

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

3. Mask

適用於 inotify_add_watch mask 與 read 返回的inotify_event中mask
IN_ACCESS 檔案被訪問
IN_ATTRIB 檔案屬性發生變化
IN_CLOSE_WRITE 以write方式開啟檔案並關閉
IN_CLOSE_NOWRITE 以非write方式開啟檔案並關閉
IN_CREATE 檔案或目錄被建立
IN_DELETE 檔案或目錄被刪除(被監測的資料夾A中B檔案被刪除)
IN_DELETE_SELF 被監測的檔案或目錄被刪除(被監測的資料夾A被刪除)
IN_MODIFY 檔案被修改
IN_MOVE_SELF 被監測的檔案或目錄移動
IN_MOVED_FROM 檔案移出被監測的目錄
IN_MOVED_TO 檔案移入被監測的目錄
IN_OPEN 檔案被開啟
上述flag的集合
IN_ALL_EVENTS 以上所有flag的集合
IN_MOVE IN_MOVED_TO|IN_MOVED_FROM
IN_CLOSE IN_CLOSE_WRITE|IN_CLOSE_NOWRITE
不常用的flag
IN_DONT_FOLLOW 不follow符號連結 (since 2.6.15)
IN_EXCL_UNLINK 當檔案從監測目中unlink後,則不再報告該檔案的相關event,比如監控/tmp使用 (since 2.6.36)
IN_MASK_ADD 追打MASK到被監測的pathname
IN_ONESHOT 只監測一次
IN_ONLYDIR 只監測目錄
僅由read返回
IN_IGNORED inotify_rm_watch,檔案被刪除或者檔案系統被umount
IN_ISDIR 發生事件的是一個目錄
IN_Q_OVERFLOW Event佇列溢位
IN_UNMOUNT 檔案系統unmount

4. 例子

用途:監測指定檔案或目錄(或不指定則為當前目錄)的一切動作。
使用:inotify [檔案或目錄]
  1. #include <unistd.h> 
  2. #include <sys/inotify.h> 
  3. #include <stdio.h> 
  4. #include <error.h> 
  5. #include <errno.h> 
  6. #include <string.h> 
  7. #define ERROR(text) error(1, errno, "%s", text)
  8. struct EventMask {   
  9. int        flag;   
  10. constchar *name;   
  11. };   
  12. int freadsome(void *dest, size_t remain, FILE *file)   
  13. {   
  14. char *offset = (char*)dest;   
  15. while (remain) {   
  16. int n = fread(offset, 1, remain, file);   
  17. if (n==0) {   
  18. return -1;   
  19.         }   
  20.         remain -= n;   
  21.         offset += n;   
  22.     }   
  23. return 0;   
  24. }   
  25. int main(int argc, char *argv[])   
  26. {   
  27. constchar *target;   
  28. if (argc == 1) {   
  29.         target = ".";   
  30.     } else {   
  31.         target = argv[1];   
  32.     }   
  33.     EventMask event_masks[] = {   
  34.            {IN_ACCESS        , "IN_ACCESS"}        ,     
  35.            {IN_ATTRIB        , "IN_ATTRIB"}        ,     
  36.            {IN_CLOSE_WRITE   , "IN_CLOSE_WRITE"}   ,     
  37.            {IN_CLOSE_NOWRITE , "IN_CLOSE_NOWRITE"} ,     
  38.            {IN_CREATE        , "IN_CREATE"}        ,     
  39.            {IN_DELETE        , "IN_DELETE"}        ,     
  40.            {IN_DELETE_SELF   , "IN_DELETE_SELF"}   ,     
  41.            {IN_MODIFY        , "IN_MODIFY"}        ,     
  42.            {IN_MOVE_SELF     , "IN_MOVE_SELF"}     ,     
  43.            {IN_MOVED_FROM    , "IN_MOVED_FROM"}    ,     
  44.            {IN_MOVED_TO      , "IN_MOVED_TO"}      ,     
  45.            {IN_OPEN          , "IN_OPEN"}          ,     
  46.            {IN_DONT_FOLLOW   , "IN_DONT_FOLLOW"}   ,     
  47.            {IN_EXCL_UNLINK   , "IN_EXCL_UNLINK"}   ,     
  48.            {IN_MASK_ADD      , "IN_MASK_ADD"}      ,     
  49.            {IN_ONESHOT       , "IN_ONESHOT"}       ,     
  50.            {IN_ONLYDIR       , "IN_ONLYDIR"}       ,     
  51.            {IN_IGNORED       , "IN_IGNORED"}       ,     
  52.            {IN_ISDIR         , "IN_ISDIR"}         ,     
  53.            {IN_Q_OVERFLOW    , "IN_Q_OVERFLOW"}    ,     
  54.            {IN_UNMOUNT       , "IN_UNMOUNT"}       ,     
  55.     };   
  56. int monitor = inotify_init();   
  57. if ( -1 == monitor ) {   
  58.         ERROR("monitor");   
  59.     }   
  60. int watcher = inotify_add_watch(monitor, target, IN_ALL_EVENTS);   
  61. if ( -1 == watcher  ) {   
  62.         ERROR("inotify_add_watch");   
  63.     }   
  64. FILE *monitor_file = fdopen(monitor, "r");   
  65. char last_name[1024];   
  66. char name[1024];   
  67. /* event:inotify_event -> name:char[event.len] */
  68. while (true) {   
  69.         inotify_event event;   
  70. if ( -1 == freadsome(&event, sizeof(event), monitor_file) ) {   
  71.             ERROR("freadsome");   
  72.         }   
  73. if (event.len) {   
  74.             freadsome(name, event.len, monitor_file);   
  75.         } else {   
  76.             sprintf(name, "FD: %d\n", event.wd);   
  77.         }   
  78. if (strcmp(name, last_name) != 0) {   
  79.             puts(name);   
  80.             strcpy(last_name, name);   
  81.         }   
  82. /* 顯示event的mask的含義 */
  83. for (int i=0; i<sizeof(event_masks)/sizeof(EventMask); ++i) {   
  84. if (event.mask & event_masks[i].flag) {   
  85.                 printf("\t%s\n", event_masks[i].name);   
  86.             }   
  87.         }   
  88.     }   
  89. return 0;   
  90. }  
  1. #include <unistd.h>
  2. #include <sys/inotify.h>
  3. #include <stdio.h>
  4. #include <error.h>
  5. #include <errno.h>
  6. #include <string.h>
  7. #define ERROR(text) e