Linux中一切皆文件,在應用程序中,有時候我們需要對文件系統的目錄或者文件進行監控,以便于我們能根據文件系統的變化來做相應的后續操作。那我們如何有效的對文件系統進行監控呢?不用苦惱,linux的前輩們已經給我們做好了,在linux2.6內核中開始引入,作為linux的系統調用來使用,所以我們就可以用它來幫助我們來完成這件事了。
接下來我們來學習一下于inotify相關的系統調用接口:
int inotify_init(void);
功能:獲得一個文件描述符,用于關聯后續的inotify事件隊列。
int inotify_add_watch(int fd, const char *pathname, uint32_t mask);
功能:在inotify文件描述符中添加新的監聽對象。
參數: fd, inotify_init函數的返回值
Pathname, 添加要監聽的文件或者目錄的路徑
Mask, 要監聽的文件或者目錄上發生的事件。
返回值:就是新添加監聽的文件描述符。
int inotify_rm_watch(int fd, int wd);
功能:從inotify的事件隊列中刪除一個監聽對象。
參數:fd, 監聽事件描述符,就是inotify_init的返回值
wd, inotify_add_watch的返回值。
有了上邊的這三個函數,我們我們就可以添加對文件或者目錄的監聽事件了,但是文件或者目錄一旦發生了變化我們又怎么能直到呢?所以我們僅僅有他們還不夠,我們還需要read函數。因為當我們添加了監聽事件后,我們需要使用select或者其他的方式來監聽我們的監聽隊列,一旦發生變化,我們就必須得用read函數讀取該描述符的數據,其中的數據就包含了我們文件的變化。read的返回值就是一個或者多個struct inotify_event的結構體,結構體的定義如下:
struct inotify_event
{
int wd; /* Watch descriptor. */
uint32_t mask; /* Watch mask. */
uint32_t cookie; /* Cookie to synchronize two events. */
uint32_t len; /* Length (including NULs) of name. */
char name __flexarr; /* Name. */
};
示例代碼如下:
#define BUF_LEN 10 * (sizeof(struct inotify_event) + NAME_MAX + 1)
#define WATCH_DIR_1 "/home/ys/test_1"
#define WATCH_DIR_2 "/home/ys/test_2"
int main(int argc, const char *argv[])
{
int init_fd;
int watch_fd_1, watch_fd_2;
int watch_mask = IN_ALL_EVENTS;
struct inotify_event *even;
char buf[BUF_LEN] = {0};
char *p = NULL;
ssize_t bytes;
//創建監聽文件描述符句柄
init_fd = inotify_init();
if (init_fd < 0)
{
perror("fail to inotify_init");
exit(1);
}
//添加監聽的目錄或者文件
watch_fd_1 = inotify_add_watch(init_fd, WATCH_DIR_1, watch_mask);
if (watch_fd_1 < 0)
{
perror("fail to inotify_add_watch 111");
exit(1);
}
//添加監聽的目錄或者文件
watch_fd_2 = inotify_add_watch(init_fd, WATCH_DIR_2, watch_mask);
if (watch_fd_2 < 0)
{
perror("fail to inotify_add_watch 222");
exit(1);
}
fd_set readfds, tempfds;
int maxfd, i = 0;
FD_ZERO(&readfds);
FD_ZERO(&tempfds);
//監聽init_fd
FD_SET(init_fd, &readfds);
maxfd = init_fd;
tempfds = readfds;
while (1)
{
tempfds = readfds;
if (select(maxfd + 1, &tempfds, NULL, NULL, NULL) < 0)
{
perror("fail to select");
break;
}
for (i = 0; i < maxfd + 1; i++)
{
if (FD_ISSET(i, &tempfds))
{
//從init_fd中讀取結構體
bytes = read(i, buf, BUF_LEN);
if (bytes < 0)
continue;
for (p = buf; p < buf + bytes;)
{
//轉換成inotify_event結構體
even = (struct inotify_event *)p;
if (even->mask & IN_CREATE)
{
if (even->wd == watch_fd_1)
printf("create new file: [%s] in %s\n", even->name, WATCH_DIR_1);
else if (even->wd == watch_fd_2)
printf("create new file: [%s] in %s\n", even->name, WATCH_DIR_2);
}
else if (even->mask & IN_DELETE)
{
if (even->wd == watch_fd_1)
printf("delete [%s] from %s\n", even->name, WATCH_DIR_1);
else if (even->wd == watch_fd_2)
printf("delete [%s] from %s\n", even->name, WATCH_DIR_2);
}
else if (even->mask & IN_IGNORED)
{
if (even->wd == watch_fd_1)
printf("%s was deleted!\n", WATCH_DIR_1);
else if (even->wd == watch_fd_2)
printf("%s was deleted!\n", WATCH_DIR_2);
inotify_rm_watch(init_fd, even->wd);
}
//p指針向后的偏移
p += sizeof(struct inotify_event) + even->len;
}
}
}
}
//刪除監聽的描述符
inotify_rm_watch(init_fd, watch_fd_1);
inotify_rm_watch(init_fd, watch_fd_2);
close(init_fd);
close(watch_fd_1);
close(watch_fd_2);
return 0;
}