使用inotify来监控系统文件

1 前言

对于linux系统的文件,如果需要监控其文件状态是否出现了增、删、改,在2.6.13或更新的linux kenerl版本上,我们可以用linux系统中提供的inotifyapi 来实现

详细的api说明可以参考: man-pages

2 应用实现

2.1 主要逻辑

关键的函数有三个

 

inotify_init() inotify_add_watch() inotify_rm_watch()

我们直接从代码实现来看api的使用

1.初始化inotify并得到文件描述符fd

 

int fd = inotify_init(); if (fd == -1) { std::cerr << "Failed to initialize inotify" << std::endl; return; }

2.添加需要监控的文件/文件夹路径 得到监控文件描述符wd

 

#define INOTIFY_FOLDER_MASK (IN_CREATE | IN_MODIFY | IN_DELETE) std::string path = "/home/xx/"; // 可以是一个目录 // std::string path = "/home/xx/test.txt" // 也可以是一个文件 int wd = inotify_add_watch(fd, path.c_str(), INOTIFY_FOLDER_MASK); if (wd == -1) { std::cerr << "Failed to add watch to [" << path << "]" << ", error:" + std::to_string(errno) << std::endl; return; }

3.通过read等待inotify事件唤醒, 并处理inotify_event

 

char buf[1024]; int len = read(fd, buf, sizeof(buf)); if (len == -1) { if (errno == EINTR) { std::cerr << "Interrupted by signal" << std::endl; } break; } std::cout << "read ok, len:" << len << std::endl; for (int i = 0; i < len;) { struct inotify_event *event = (struct inotify_event *)&buf[i]; i += sizeof(struct inotify_event) + event->len; if (event->mask & IN_CREATE) { std::cout << "File created: " << event->name << std::endl; } else if (event->mask & IN_MODIFY) { std::cout << "File modified: " << event->name << std::endl; } else if (event->mask & IN_DELETE) { std::cout << "File deleted: " << event->name << std::endl; } }

4.inotify_rm_watch 移除监控

 

if (fd == -1) { return; } if (wd != -1) { inotify_rm_watch(fd, wd); } close(fd);

2.2 注意事项

在实际场景中,我们通过step3拿到了inotify_event,如何判断这是否是我们监控的目标文件,这需要根据step2中监控的path本身是文件还是目录来针对性处理

2.2.1 inotify path为文件的处理

检查event中的wd是否和step2中拿到的一致

 

event->wd == wd

注意这种情况下拿到的event->name实际上是空的

2.2.2 inotify path为目录的处理

检查event->name

 

event->name == targetName // targetName即为你这个目录中你要看的文件名 例如test.txt

2.3 逻辑优化

实际业务中可以把这些处理封装到一个FileMonitor类当中,对于变动文件的后处理也可以作为std::functionalCallback灵活添加实现

 

enum MONI_TYPE { MONI_FILE, MONI_FOLDER, MONI_END, }; class FileMonitor { public: FileMonitor(); FileMonitor(std::string str); ~FileMonitor(); void monitor(); void registerHandle(std::function<void(std::string)>); void setTargetFileName(std::string name); static void stopRun(); private: int fd; int wd; std::string path; std::string targetfileName; MONI_TYPE moniType; static bool run; void init(); void exit(); void checkType(); void addDeviceInotify(); bool match(std::string, int); std::string getRealPath(); std::function<void(std::string)> callBack; };

自定义Callback, 例如发现目标文件变动后我需要读取它

 

void CallBack(std::string str) { std::string line; std::ifstream ifs(str); if (!ifs.good()) { std::cerr << "Failed to open file: " << str << std::endl; return; } // just read first for test if (std::getline(ifs, line)) { std::cout << "Read line: " << line << std::endl; } } int main() { std::string pathStr = "/home/xx/"; FileMonitor monitor(pathStr); monitor.registerHandle(CallBack); }

文件变动后调用Callback

 

if (event->mask & IN_MODIFY) { std::cout << "File modified: " << event->name << std::endl; if (event->wd == wd) { if (callBack) { callBack(path); } else { std::cerr << "No handle function registered" << std::endl; } } }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值