Linux提供inotify機制來監控文件事件,簡單流程如下:
- inotify_init創建inotify實例,成功會返回一個文件描述符
- inotify_add_watch添加要監控文件或目錄,添加成功返回監控描述符
- read讀取inotify實例文件描述符,獲得文件事件
需要注意的是inotify監控機制非遞歸的,即子目錄也需要通過inotify_add_watch添加監控列表
### inotify_init 創建inotify_init實例
```c
// return file descriptor on success, or -1 on error
int inotify_ini(void)
```
### inotify_add_watch 添加監控項
```c
// return watch descriptor on success, or -1 on error
int inotify_add_watch(int fd, const char *pathname, unit32_t mask)
```
- fd指inotify_init返回的文件描述符
- filename指被監控的文件或目錄
- mask掩碼,用于指定監控事件
### inotify_rm_watch 刪除監控項
```c
// return 0 on success, or -1 on error
int inotify_rm_watch(int fd, unit32_t wd)
```
- wd為監控項描述符
刪除監控項會生成IN_IGNORED事件
### 讀取inotify事件
read通過inotify文件描述符讀取事件,當事件發生時,返回一個或多個inotify_event結構
```c
struct inotify_event {
int wd, // 監控項描述符
unit32_t mask, // 描述該事件的位掩碼
unit32_t cookie, // 用于聯系兩個事件,例如重命名子目錄或子文件則會發送IN_MOVE_FROM和IN_MOVE_TO兩個事件,兩者inotify.cookie是一樣的
unit32_t len,
char name[]
}
```
### 掩碼
- IN_ACCESS 文件被訪問
- IN_ATTRIB 文件元數據被修改(例如文件權限)
- IN_CREATE 在監控目錄中創建子目錄或文件
- IN_MODIFY 文件被修改
- IN_OPEN 文件被打開
- IN_CLOSE_WRITE 關閉可寫文件
- IN_CLOSE_NOWRITE 關閉以只讀方式打開的文件
- IN_DELETE 刪除監控目錄下的子目錄或文件
- IN_DELETE_SELF 刪除監控目錄
- IN_MOVE_FROM 從監控目錄移除子目錄或文件
- IN_MOVE_TO 文件移動到監控目錄
- IN_MOVE_SELF 移動監控目錄或監控文件(或重命名監控目錄,文件,如果是重命名子目錄或子文件則會發送IN_MOVE_FROM和IN_MOVE_TO兩個事件,兩者inotify.cookie是一樣的)
下面只能添加監控項使用
- IN_MASK_ADD 將事件追加到pathname當前掩碼,當指定這個并且對同個pathname執行兩次添加監控項,掩碼不會覆蓋而是合并
- IN_ONLYDIR pathname只能是目錄,否則inotify_add_watch調用失敗,報錯ENOTDIR
- IN_ONESHOT 只監控pathname一個事件,事件發生后,自動從監控列表消失
- IN_ALL_EVENTS 所有輸出事件的總稱
下面只能讀取事件時使用
- IN_IGNORED 移除監控項
- IN_ISDIR name返回的文件名為路徑
- IN_Q_OVERFLOW 事件隊列移除
### demo
```c
#include <sys/inotify.h>
#include <limits.h>
#include "tlpi_hdr.h"
#define BUF_LEN 10 * (sizeof(struct inotify_event) + NAME_MAX + 1)
void displayInotifyEvent(struct inotify_event *i)
{
printf(" wd =%2d; ", i->wd);
if (i->cookie > 0)
printf("cookie =%4d; ", i->cookie);
printf("mask = ");
if (i->mask & IN_ACCESS) printf("IN_ACCESS ");
if (i->mask & IN_ATTRIB) printf("IN_ATTRIB ");
if (i->mask & IN_CLOSE_NOWRITE) printf("IN_CLOSE_NOWRITE ");
if (i->mask & IN_CLOSE_WRITE) printf("IN_CLOSE_WRITE ");
if (i->mask & IN_CREATE) printf("IN_CREATE ");
if (i->mask & IN_DELETE) printf("IN_DELETE ");
if (i->mask & IN_DELETE_SELF) printf("IN_DELETE_SELF ");
if (i->mask & IN_IGNORED) printf("IN_IGNORED ");
if (i->mask & IN_ISDIR) printf("IN_ISDIR ");
if (i->mask & IN_MODIFY) printf("IN_MODIFY ");
if (i->mask & IN_MOVE_SELF) printf("IN_MOVE_SELF ");
if (i->mask & IN_MOVED_FROM) printf("IN_MOVED_FROM ");
if (i->mask & IN_MOVED_TO) printf("IN_MOVED_TO ");
if (i->mask & IN_OPEN) printf("IN_OPEN ");
if (i->mask & IN_Q_OVERFLOW) printf("IN_Q_OVERFLOW ");
if (i->mask & IN_UNMOUNT) printf("IN_UNMOUNT ");
printf("\n");
if (i->len > 0)
printf(" name = %s\n", i->name);
}
int main(int argc, char const *argv[])
{
int i, fd, wd;
char *p;
ssize_t numRead;
char buf[BUF_LEN];
struct inotify_event *event;
if (argc < 2 || strcmp(argv[1], "--help") == 0)
{
usageErr("%s pathname", argv[0]);
}
fd = inotify_init();
if (fd == -1)
{
errExit("inotify_init failed \n");
}
for (i = 0; i < argc - 1; ++i)
{
wd = inotify_add_watch(fd, argv[i + 1], IN_ALL_EVENTS);
if ( wd == -1)
{
errExit("inotify_add_watch failed \n");
}
else
{
printf("watching %s using wd %d \n", argv[i + 1], wd);
}
}
for (;;)
{
numRead = read(fd, buf, BUF_LEN);
if (numRead == 0)
{
fatal("read from inotify fd returned 0 \n");
}
if (numRead == -1)
{
errExit("read failed\n");
}
printf("read %ld bytes from inotify fd\n", (long)numRead);
for (p = buf; p < buf + numRead;)
{
event = (struct inotify_event *)p;
displayInotifyEvent(event);
p += sizeof(struct inotify_event) + event->len;
}
}
return 0;
}
```
### 相關鏈接
- [我用inotify實現的一個php擴展](https://github.com/wuzhc/php-inotify)
### 參考
- Linux系統編程手冊(上冊)
- php
- 編譯安裝
- 基本概念
- 垃圾回收機制
- 生命周期
- zval底層實現
- c擴展開發
- gdb調試工具
- 自定義擴展簡單demo
- 鉤子函數
- 讀取php.ini配置
- 數組
- 函數
- 類
- yaf擴展底層源碼
- swoole擴展底層源碼
- memoryGlobal內存池
- swoole協程使用記錄
- 單點登錄sso原理
- compser使用
- session實現機制
- c & linux
- gcc
- 指針
- 結構體,聯合和位字段
- 宏定義井號說明
- printf家族函數和可變參數
- 共享函數
- 靜態庫和動態庫
- makefile自動化構建
- 信號一
- 信號二
- inotify監控文件事件
- socket編程
- 簡介
- UNIX DOMAIN
- Internet DOMAIN
- TCP/IP
- 文件IO多路復用
- 內存管理
- 進程組,會話和控制終端
- daemon守護進程
- 多進程
- 多線程
- 常用進制轉換
- go
- 入門知識
- 字節和整數裝換
- python
- redis
- 應用場景
- 消息隊列
- 熱點數據
- 掃碼登錄
- 訂閱發布
- 次數限制
- 搶購超賣
- 持久化機制
- mysql
- 工作流程
- MyISAM和InnoDB區別
- 用戶和權限管理
- 執行計劃
- sql優化
- 事務和鎖
- 慢查詢日志
- case...when...then...end用法
- sql
- 參考
- linux
- 內核參數優化
- 防火墻設置
- docker
- docker入門知識
- 算法
- 多維數組合
- DFA算法
- 紅包金額分配