【C++ 系統控制 #2】C++ inotify sample code 偵測指定路徑底下的文件變化 (內有範例程式碼)

基礎概念

inotify 是取用 linux 底下的系統自動監聽檔案變化的方式,
在 C++ 中,當我們獲得了系統給的 event,我們會得到該檔案的「檔名」,
我們就能再進一步依照此絕對路徑做對應的資料操作。

注意:inotify 的功能目前只在 linux 系統能使用,mac 上不能使用哦~ (自己親自測試過QQ)

使用範例

inotify 做到的效果就是:如果當某個資料夾底下有資料變化,會告訴你「檔名」
舉一些例子例如:

  • 新增:IN_CREATE
  • 修改:IN_MODIFY
  • 刪除:IN_DELETE
  • 資料被開啟:IN_OPEN
  • 資料屬性變化:IN_ATTRIB (可搭配touch使用,獲得目標檔案路徑)

下方程式碼說明

這是一個範例程式碼,
用途是透過無限迴圈偵測指定資料夾路徑 “./target_path/” 底下的「不間斷的」檔案變化。

Sample Code

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/inotify.h>
#include <unistd.h>
#include <iostream>
#include <cxxabi.h>
#include <typeinfo>

#define EVENT_SIZE  (sizeof(struct inotify_event))
#define BUF_LEN     (1024 * (EVENT_SIZE + 16))

using namespace std;


void get_file_path_loop(string watch_path){

  char buffer[BUF_LEN];
  int length, i = 0;
  int fd, wd;

  /* https://man7.org/linux/man-pages/man7/inotify.7.html */
  fd = inotify_init();

  if (fd < 0) {
      perror("inotify_init");
  }

  wd = inotify_add_watch(fd, watch_path.c_str(), IN_MODIFY | IN_CREATE | IN_DELETE | IN_ATTRIB);  

  while(1){   
    length = read(fd, buffer, BUF_LEN);  
    printf("[Event] The file length = %d
", length);

    if (length < 0) {
        perror("read");
    }

    i = 0;
    while (i < length) {
        struct inotify_event *event = (struct inotify_event *) &buffer[i];

        if (event->len) {
            if (event->mask & IN_CREATE) {
                printf("[Event IN_CREATE] The file %s/%s was created.
", watch_path.c_str(), event->name);
            } else if (event->mask & IN_DELETE) {
                printf("[Event IN_DELETE] The file %s/%s was deleted.
", watch_path.c_str(), event->name);
            } else if (event->mask & IN_MODIFY) {
                printf("[Event IN_MODIFY] The file %s/%s was modified.
", watch_path.c_str(), event->name);
            } else if (event->mask & IN_ATTRIB) {
                printf("[Event IN_ATTRIB] The file %s/%s was IN_ATTRIB.
", watch_path.c_str(), event->name);  
            }
        }
        i += EVENT_SIZE + event->len;
    }
  }


  (void) inotify_rm_watch(fd, wd);
  (void) close(fd);
}

int main(int argc, char **argv) {
    string watch_path = "./target_path/";
    get_file_path_loop(watch_path);    

    return 0;
}

Reference