概述
inotify系列接口是为了实现监听文件系统的变化而开发的。inotify功能可以监听文件夹或者文件,如果被监听的对象是文件夹,那么除了可以监听文件夹本身的事件外(例如IN_DELETE_SELF),也会监听位于其内部的文件事件(例如IN_CREATE)。
基本概念
对于大脑来说还是具象化的东西容易理解容易和记忆。但是生活中为了更加高效的传递信息就必须去冗余也就是抽象化,因为越抽象其所能表示的信息则越广泛。
- watch
一个监听对象,例如一个文件夹或者一个文件。成功调用inotify_add_watch接口后就会生成一个watch的文件句柄,并会将其加入inotify instant中去。 - inotify instant
是所有watch的入口点,所有watch的事件都通过read该instant获取。在成功调用inotify_init接口后被创建。 - inotify_event
用于记录文件系统中的事件变化。其定义如下
struct inotify_event {
int wd; /* Watch descriptor */
uint32_t mask; /* Mask describing event */
uint32_t cookie; /* Unique cookie associating related
events (for rename(2)) */
uint32_t len; /* Size of name field */
char name[]; /* Optional null-terminated name */
};
API
inotify提供的api则是非常的简洁。
- inotify_init()
初始化一个inotify instant并且返回一个已分配好inotify事件队列的inotify文件句柄,后面所有挂载其下的watch都通过read接口去读取改文件句柄获取事件。 - inotify_add_watch()
用于添加一个watch到已经初始化的inotify instant中去。成功调用后则会返回一个非零的该watch文件句柄。 - inotify_rm_watch
从一个inotify instant中删除一个watch。
应用例子
- inotifyTest.c
/**
*
* usage:
* ./argv[1] <watch1>
*/
#include <stdio.h>
#include <sys/inotify.h>
#include <unistd.h>
#include <string.h>
#define PATH_INDEX 1
struct consoleCmd{
int argc;
char** argv;
};
struct watchInfo{
int fd;
char* path;
};
#define EVT_BUF_MAX 200
struct inotifyEvtBuf{
char buf[EVT_BUF_MAX];
ssize_t size;
};
struct inotifyInfo{
int inotifyFd;
struct watchInfo wif;
struct inotifyEvtBuf iEvtBuf;
struct consoleCmd* ccmd;
};
void initCosoleCmd(struct inotifyInfo* ii , int argc, char** argv)
{
struct consoleCmd* ccmd = ii->ccmd;
if(ccmd == NULL){
perror("The ccmd is NULL\n");
return;
}
ccmd->argc = argc;
ccmd->argv = argv;
}
uint32_t getFileMask()
{
return (uint32_t)(IN_CREATE|IN_DELETE);
}
/**
* Used to get watch infomation from console.
*/
void parseWatch(struct inotifyInfo* ii)
{
ii->wif.path = ii->ccmd->argv[PATH_INDEX];
}
void initWatchFileInfo(struct inotifyInfo*ii, uint32_t watchMask)
{
struct consoleCmd* ccmd = ii->ccmd;
struct watchInfo* wif = &ii->wif;
parseWatch(ii);
//Getting inotify instant.
ii->inotifyFd = inotify_init();
if(ii->inotifyFd < 0){
perror("Getting inotify instant is fail\n");
return;
}
wif->fd = inotify_add_watch(ii->inotifyFd,
wif->path, watchMask);
if(wif->fd< 0){
perror("Adding watch is fail.\n");
return;
}
}
void clearEvtBuf(struct inotifyInfo* ii)
{
struct inotifyEvtBuf* iEvtBuf = &ii->iEvtBuf;
memset(iEvtBuf->buf, 0, EVT_BUF_MAX);
iEvtBuf->size = 0;
}
ssize_t monitorWatch(struct inotifyInfo* ii)
{
clearEvtBuf(ii);
return read(ii->inotifyFd, ii->iEvtBuf.buf, EVT_BUF_MAX);
}
void inotifyLooper(struct inotifyInfo* ii)
{
while(monitorWatch(ii)){
struct inotify_event* evt = (struct inotify_event*)ii->iEvtBuf.buf;
if(evt->wd == ii->wif.fd){
if(evt->mask&IN_CREATE){
printf("%s is created.\n", evt->name);
}else if(evt->mask&IN_DELETE){
printf("%s is deleted\n", evt->name);
}else{
printf("This operaation can't be recognizeed for %s\n", evt->name);
}
}
}
}
int main(int argc, char** argv)
{
struct consoleCmd ccmd;
struct inotifyInfo mInotifyInfo;
mInotifyInfo.ccmd = &ccmd;
initCosoleCmd(&mInotifyInfo, argc, argv);
initWatchFileInfo(&mInotifyInfo, getFileMask());
inotifyLooper(&mInotifyInfo);
inotify_rm_watch(mInotifyInfo.inotifyFd, mInotifyInfo.wif.fd);
return 0;
}
- Makefile
OBJ:=inotifyTest
EXT:=c
SRC:=$(OBJ).$(EXT)
GCC=gcc
$(OBJ):$(SRC)
$(GCC) -o $@ $^
clean:
rm -f $(OBJ)
- 测试
$make
$mkdir watch1
$./inotifyTest watch1/&
$touch watch1/subDir
subDir is created.
$rm -rf watch1/subDir
subDir is deleted
可以看到在被监听的目录下已经可以跟踪文件内部的文件变化了。
gitee仓库源码
https://gitee.com/solo-king/AllTestingFromLinux/blob/master/c/examples/inotify/inotifyTest.c