文件系统事件监听
文件系统事件和网络IO事件一样,也可以通过epoll或者IOCP 事件管理器统一调度,当所监控的文件或文件夹发生了增删改的事件时,就会触发事件回调,进行事件处理。很常见的应用,如配置文件立即生效功能,就可以通过这种方式触发软件内部进行配置更新。也可以用来监控日志文件的更新,拉取最新日志(类似notepad++打开日志文件,如果日志文件更新了,就会提示reload)。
下面分别给出了linux和windows系统下文件系统事件监听的示意代码,仅供参考。
//file: FileMonitor.h#ifndef INOTIFY_FILEMONITOR_H
#define INOTIFY_FILEMONITOR_H#include <string>
#include <map>/*** 文件监视器。* 用于监控文件系统中文件相关的事件,如创建、删除等操作。*/
class FileMonitor {public:FileMonitor() = default;~FileMonitor() = default;void startWatch(const std::string &path);void stopWatch();bool addWatch(const std::string &path);private:// inotify 句柄int inotify_fd{0};// inotify_add_watch返回值 -> 要监控的文件名 的映射std::map<int, std::string> watchDesc2Name;// 是否停止监控bool isStopped{false};
};#endif //INOTIFY_FILEMONITOR_H// file: FileMonitor.cpp#include <sys/inotify.h>
#include <sys/epoll.h>
#include <unistd.h>
#include <thread>
#include <chrono>
#include <cstdio>
#include <iostream>
#include "FileMonitor.h"#define log(format, ...) { \auto now = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()); \char buf[64]; \strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", std::localtime(&now)); \printf("%s | %llu | ", buf, std::this_thread::get_id()); \printf(format, ##__VA_ARGS__); \printf("\n"); }#define EVENT_SIZE ( sizeof (struct inotify_event) )
#define BUF_LEN ( 1024 * ( EVENT_SIZE + 16 ) )void FileMonitor::startWatch(const std::string &path) {log("Ready to watch...");// inotify 初始化inotify_fd = inotify_init();if (!addWatch(path)) {return;}// 创建一个 epoll 句柄log("epoll_create");int epfd = epoll_create(256);struct epoll_event ev;ev.data.fd = inotify_fd; // 设置要处理的事件相关的文件描述符ev.events = EPOLLIN | EPOLLET; // 设置要处理的事件类型// 注册 epoll 事件log("epoll_ctl");epoll_ctl(epfd, EPOLL_CTL_ADD, inotify_fd, &ev);// 循环监听事件char buffer[BUF_LEN];struct epoll_event events[20]; // 存储从内核得到的事件集合while (!isStopped) {log("epoll_wait...");// 等待事件发生。返回需要处理的事件数目int nfds = epoll_wait(epfd, events, 20, 500);log("Event count: %d", nfds);for (int i = 0; i < nfds; ++i) {/*** epoll_wait 会一直阻塞直到下面2种情况:* 1. 一个文件描述符触发了事件。* 2. 被一个信号处理函数打断,或者 timeout 超时。* 所以下面需要对 fd 进行过滤,判断是否是我们需要的 fd 产生了事件*/if (events[i].data.fd != inotify_fd) {log("Other event, fd=%d", events[i].data.fd);continue;}long length = read(inotify_fd, buffer, BUF_LEN);if (length < 0) {perror("Read failed");}log("Read length: %ld", length);int pos = 0;int count = 0;while (pos < length) {struct inotify_event *event = (struct inotify_event *) &buffer[pos];log("[%d]event->len=%u, event->mask=%#X, EVENT_SIZE=%lu", ++count, event->len, event->mask, EVENT_SIZE);if (event->len) {if (event->mask & IN_CREATE) {log("CREATE: %s", event->name);} else if (event->mask & IN_DELETE) {log("DELETE: %s", event->name);} else if (event->mask & IN_MODIFY) {log("MODIFY: %s", event->name);} else if (event->mask & IN_OPEN) {log("OPEN: %s", event->name);} else if (event->mask & IN_CLOSE) {log("CLOSE: %s", event->name);} else {log("Unknown event, mask=%u", event->mask);}}pos += EVENT_SIZE + event->len;}}}log("Stop inotify");for (auto &ele: watchDesc2Name) {inotify_rm_watch(inotify_fd, ele.first);}close(epfd);close(inotify_fd);
}void FileMonitor::stopWatch() {isStopped = true;
}bool FileMonitor::addWatch(const std::string &path) {// TODO 需要对文件(夹)是否存在进行判断// 监听指定目录下的修改、创建、删除事件int wd = inotify_add_watch(inotify_fd, path.c_str(), IN_MODIFY | IN_CREATE | IN_DELETE);
// int wd = inotify_add_watch(inotify_fd, path.c_str(), IN_ALL_EVENTS);if (wd < 0) {log("inotify_add_watch failed: %s", path.c_str());return false;}log("Add watch: %s", path.c_str());watchDesc2Name[wd] = path;return true;
}// main: main.cpp
#include <iostream>
#include "FileMonitor.h"int main() {std::string dirPath = "/home/nvidia/logs";FileMonitor fileMonitor;fileMonitor.startWatch(dirPath);return 0;
}// https://github.com/BornToDeath/cpp/blob/main/test/case11_inotify/main.cpp
#include <iostream>
#include <map>
#include <windows.h>
#define DIRECTORY_PATH L"C://TestFolder"#define CONTAINING_RECORD(address, type, field) ((type *)( \(PCHAR)(address) - \(ULONG_PTR)(&((type *)0)->field)))typedef struct directory_info
{HANDLE hDir;CHAR szDirName[MAX_PATH];CHAR szBuffer[4096];DWORD dwBufLength;OVERLAPPED Overlapped; // 此处需要定义overlapp结构
}DIRECTORY_INFO, * LPDIRECTORY_INFO;class cFileUpdateChecker
{
public:cFileUpdateChecker(const wchar_t* root) :hThread(NULL), dwThread(0), hComp(NULL), pdir(NULL) { wsprintf(dirPath,L"%s",root); }~cFileUpdateChecker(){if (hComp) {PostQueuedCompletionStatus(hComp, 0, NULL, NULL);CloseHandle(hComp);}if (hThread) CloseHandle(hThread);if (pdir){CloseHandle(pdir->hDir);HeapFree(GetProcessHeap(), 0, pdir);}for(auto it = opened_files.begin();it!=opened_files.end();it++){if(it->second != NULL)CloseHandle(it->second);}}// 定义IOCP的工作线程static DWORD WINAPI ThreadFunc(void* p){cFileUpdateChecker* pHost = (cFileUpdateChecker*)p;LPDIRECTORY_INFO lpdir = NULL;DWORD nbytes, errCode;LPOVERLAPPED lpOverlapped = NULL;PFILE_NOTIFY_INFORMATION fni = NULL;ULONG_PTR completion_key;DWORD wait = 1000;while (true){BOOL bRet = GetQueuedCompletionStatus(pHost->hComp, &nbytes, &completion_key, &lpOverlapped, wait);if (FALSE == bRet ){ errCode = GetLastError();if (errCode == WAIT_TIMEOUT){wait = INFINITE;continue;}elsebreak;}if (lpOverlapped == NULL){break;}else{lpdir = CONTAINING_RECORD(lpOverlapped, DIRECTORY_INFO, Overlapped);if (lpdir){fni = (PFILE_NOTIFY_INFORMATION)lpdir->szBuffer;int filename_length =fni->FileNameLength;wchar_t* root_dir = (wchar_t*)lpdir->szDirName;wchar_t* filename = &fni->FileName[0];switch (fni->Action){case FILE_ACTION_ADDED:wprintf(L"The file %s/%s was added to the directory.\r\n", root_dir, filename);break;case FILE_ACTION_REMOVED:wprintf(L"The file %s/%s was removed from the directory.\r\n", root_dir, filename);break;case FILE_ACTION_MODIFIED:{wchar_t file_path_buffer[MAX_PATH]={};wsprintf(file_path_buffer,L"%s\\%s",root_dir, filename);wprintf(L"The file %s was modified. This can be a change in the time stamp or attributes.\r\n", file_path_buffer);auto it = pHost->opened_files.find(file_path_buffer);if(it == pHost->opened_files.end()){HANDLE hFile = CreateFile(file_path_buffer,GENERIC_READ,FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);if(hFile != NULL){DWORD dwFilePointer = SetFilePointer(hFile,0,NULL,FILE_END);if(dwFilePointer != INVALID_SET_FILE_POINTER)pHost->opened_files[file_path_buffer]=hFile;elseCloseHandle(hFile);}}else{CHAR szReadText[50] = {};DWORD dwRead = 0;//需要注意的是,FILE_ACTION_MODIFIED信号仅表示文件系统中的该文件节点对象的写状态更新了,至于是否完成落盘,还需要看修改文件的进程是否完成了刷盘。由于实时性问题,刷盘动作可能存在一定的滞后,如果每次进入Modify事件都要增量读取更新的文件内容。可以增加30~50ms的延时bRet = ReadFile(it->second,szReadText,32,&dwRead,NULL);if(bRet == FALSE){CloseHandle(it->second);pHost->opened_files.erase(it);}else{printf("Additional file content: %s.\r\n",szReadText);SetFilePointer(it->second,0,NULL,FILE_END);}}}break;case FILE_ACTION_RENAMED_OLD_NAME:{const wchar_t* new_filename = L"";int new_filename_length = 0;if (fni->NextEntryOffset);{PFILE_NOTIFY_INFORMATION new_fni = (PFILE_NOTIFY_INFORMATION)(lpdir->szBuffer + fni->NextEntryOffset);new_filename = &new_fni->FileName[0];new_filename_length = new_fni->FileNameLength;}wprintf(L"The file %s/%s was renamed, and this is the new name %s.\r\n", root_dir, filename, new_filename);}break;case FILE_ACTION_RENAMED_NEW_NAME:wprintf(L"The file %s/%s was renamed and this is the new name.\r\n", root_dir, filename);break;default:break;}// re post eventZeroMemory(&(pHost->pdir->Overlapped), sizeof(OVERLAPPED));ZeroMemory(pHost->pdir->szBuffer, 4096);ReadDirectoryChangesW(pHost->pdir->hDir,pHost->pdir->szBuffer,sizeof(pHost->pdir->szBuffer),TRUE,FILE_NOTIFY_CHANGE_FILE_NAME |FILE_NOTIFY_CHANGE_DIR_NAME |FILE_NOTIFY_CHANGE_ATTRIBUTES |FILE_NOTIFY_CHANGE_SIZE |FILE_NOTIFY_CHANGE_LAST_ACCESS |FILE_NOTIFY_CHANGE_CREATION |FILE_NOTIFY_CHANGE_SECURITY |FILE_NOTIFY_CHANGE_LAST_WRITE,&(pHost->pdir->dwBufLength),(OVERLAPPED*)(&(pHost->pdir->Overlapped)),NULL);}}}return 0;}bool StartChecker(){hComp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);pdir = (LPDIRECTORY_INFO)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(DIRECTORY_INFO));if (NULL == pdir){return false;}pdir->hDir = CreateFile(dirPath,FILE_LIST_DIRECTORY,FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,NULL,OPEN_EXISTING,FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED,NULL);if (pdir->hDir == INVALID_HANDLE_VALUE){return false;}// 启动工作线程hThread = CreateThread(NULL, 0, ThreadFunc, this, 0, &dwThread);if (NULL == hThread){return false;}ZeroMemory(&(pdir->Overlapped), sizeof(OVERLAPPED));ZeroMemory(pdir->szBuffer, 4096);ZeroMemory(pdir->szDirName, MAX_PATH);wsprintf((wchar_t*)pdir->szDirName,L"%s", dirPath);// 投递I/O请求到完成端口HANDLE hRet = CreateIoCompletionPort(pdir->hDir, hComp,NULL, 0);if (NULL == hComp){return false;}BOOL bRet = ReadDirectoryChangesW(pdir->hDir,pdir->szBuffer,4096,TRUE,FILE_NOTIFY_CHANGE_FILE_NAME |FILE_NOTIFY_CHANGE_DIR_NAME |FILE_NOTIFY_CHANGE_ATTRIBUTES |FILE_NOTIFY_CHANGE_SIZE |FILE_NOTIFY_CHANGE_LAST_ACCESS |FILE_NOTIFY_CHANGE_CREATION |FILE_NOTIFY_CHANGE_SECURITY |FILE_NOTIFY_CHANGE_LAST_WRITE,&pdir->dwBufLength,&(pdir->Overlapped),NULL);if (FALSE == bRet){return false;}return true;}
private:HANDLE hThread;DWORD dwThread;HANDLE hComp;LPDIRECTORY_INFO pdir;WCHAR dirPath[MAX_PATH];std::map<std::wstring,HANDLE> opened_files;
};int main()
{cFileUpdateChecker* ckr = new cFileUpdateChecker(DIRECTORY_PATH);std::cout << "Supervise "; std::wcout << DIRECTORY_PATH << " Begin..." << std::endl;ckr->StartChecker();getchar();delete ckr;getchar();
}// https://blog.csdn.net/nhn_devlab/article/details/6034055
相关文章:
文件系统事件监听
文件系统事件和网络IO事件一样,也可以通过epoll或者IOCP 事件管理器统一调度,当所监控的文件或文件夹发生了增删改的事件时,就会触发事件回调,进行事件处理。很常见的应用,如配置文件立即生效功能,就可以通…...
探秘HTTPS:如何通过SSL/TLS保证网络通信安全
目录 引言 详解HTTPS加密实现机制 SSL/TLS工作原理 结论 引言 随着网络安全威胁的日益增加,HTTPS通过SSL(Secure Sockets Layer)和TLS(Transport Layer Security)协议提供的加密技术变得至关重要。这些技术保证了用…...
Java算法之动态规划
Java算法之动态规划 前言 最近这一段时间一直在刷算法题,基本上一有时间就会做一两道,这两天做了几道动态规划的问题,动态规划之前一直是我比较头疼的一个问题,感觉好复杂,一遇到这样的问题就想跳过,昨…...
C++从零开始的打怪升级之路(day47)
这是关于一个普通双非本科大一学生的C的学习记录贴 在此前,我学了一点点C语言还有简单的数据结构,如果有小伙伴想和我一起学习的,可以私信我交流分享学习资料 那么开启正题 今天分享的是关于set和map的知识点 1.关联式容器 在前面&#…...
香橙派AIpro开发板开箱测评
2023年12月,香橙派联合华为发布了基于昇腾的Orange Pi AIpro开发板,提供8/20TOPS澎湃算力,能覆盖生态开发板者的主流应用场景,让用户实践各种创新场景,并为其提供配套的软硬件。香橙派AIpro开发板一经发布便吸引了众多…...
ISP基础概述
原文来自ISP 和摄像头基本知识 本文主要介绍ISP,以供读者能够理解该技术的定义、原理、应用。 🎬个人简介:一个全栈工程师的升级之路! 📋个人专栏:计算机杂记 🎀CSDN主页 发狂的小花 dz…...
C++第一弹---C++入门(上)
✨个人主页: 熬夜学编程的小林 💗系列专栏: 【C语言详解】 【数据结构详解】 【C详解】 C入门 1、C关键字(C98) 2、命名空间 2.1、命名空间定义 2.2、命名空间使用 3、C输入&输出 4、缺省参数 4.1、缺省参数概念 4.2、缺省参…...
VScode格式化快捷键
vscode格式化代码快捷键 如何使用快捷键格式化代码。使用Java的格式去设置,发现不起作用。 在这里记录一下: 在Windows中,vscode格式化代码快捷键是“ShiftAltF”; 在Mac中,vscode格式化代码快捷键是“ShiftOption…...
HCIP---IS-IS协议
文章目录 前言一、pandas是什么?二、使用步骤 1.引入库2.读入数据总结 一.IS-IS协议概述 IS-IS是一种基于链路状态的内部网关协议(IGP),它使用最短路径优先算法(SPF或Dijkstra)进行路由计算。这种协议在自治…...
突破编程_C++_设计模式(组合模式)
1 组合模式的基本概念 C中的组合模式是一种对象结构型模式,它将多个对象组合成树形结构,以表示具有整体-部分关系的层次结构。在这个模式中,对单个对象(叶子对象)与组合对象(容器对象)的使用具…...
010Editor汉化版+下载+注册码+模板bug
项目场景: 这天我想使用我的不知名的一个破解版本的010Edit来查看一个EXE程序,并想使用模板功能,但是发现没有该模板还无法下载最新模板 问题描述 010Edit联网后需要注册码: 010 Editor 激活码生成器 使用方法 参照教程使用0…...
js【详解】BOM
浏览器对象模型 (Browser obiect Mode 简称 BOM) 浏览器对象即 window,调用window对象的属性和方法时,可以省略window window 常用的属性 Navigator 常用于获取浏览器的信息 navigator.userAgent;火狐浏览器范例: “…...
Leetcode 3077. Maximum Strength of K Disjoint Subarrays
Leetcode 3077. Maximum Strength of K Disjoint Subarrays 1. 解题思路 1. 朴素思路2. 算法优化 2. 代码实现 题目链接:3077. Maximum Strength of K Disjoint Subarrays 1. 解题思路 这道题很惭愧没有搞定,思路上出现了差错,导致一直没能…...
【JetsonNano】onnxruntime-gpu 环境编译和安装,支持 Python 和 C++ 开发
1. 设备 2. 环境 sudo apt-get install protobuf-compiler libprotoc-devexport PATH/usr/local/cuda/bin:${PATH} export CUDA_PATH/usr/local/cuda export cuDNN_PATH/usr/lib/aarch64-linux-gnu export CMAKE_ARGS"-DONNX_CUSTOM_PROTOC_EXECUTABLE/usr/bin/protoc&qu…...
知名比特币质押协议项目Babylon确认参加Hack.Summit()2024区块链开发者大会
Babylon项目已确认将派遣其项目代表出席2024年在香港数码港举办的Hack.Summit()2024区块链开发者大会。作为比特币生态的领军项目,Babylon积极参与全球区块链领域的交流与合作,此次出席大会将为其提供一个展示项目进展、交流技术与创新思路的重要平台。B…...
如何学习、上手点云算法(三):用VsCode、Visual Studio来debug基于PCL、Open3D的代码
写在前面 本文内容 以PCL 1.14.0,Open3D0.14.1为例,对基于PCL、Open3D开发的代码进行源码debug; 如何学习、上手点云算法系列: 如何学习、上手点云算法(一):点云基础 如何学习、上手点云算法(二):点云处理相…...
【干货】alzet渗透泵操作说明
alzet渗透泵是一款小型、可植入式的胶囊渗透泵产品,此产品由于其独特的渗透原理,深受广大科研人员的喜爱。该泵可适用于小鼠、大鼠及其他实验动物的研究,并且alzet渗透泵可减轻科研人员夜间及周末给药的困扰。alzet渗透泵无需外部连接或频繁处…...
CVPR 2022 Oral | Bailando: 基于编舞记忆和Actor-Critic GPT的3D舞蹈生成
目录 测试结果: 02 提出的方法 测试结果: 预测有3个步骤,速度比较慢 02 提出的方法 1. 针对舞蹈序列的VQ-VAE和编舞记忆 与之前的方法不同,我们不学习从音频特征到 3D 关键点序列的连续域的直接映射。相反,我们先让…...
解读电影级视频生成模型 MovieFactory
Diffusion Models视频生成-博客汇总 前言:MovieFactory是第一个全自动电影生成模型,可以根据用户输入的文本信息自动扩写剧本,并生成电影级视频。其中针对预训练的图像生成模型与视频模型之间的gap提出了微调方法非常值得借鉴。这篇博客详细解读一下这篇论文《MovieFactory:…...
【Python从入门到进阶】50、当当网Scrapy项目实战(三)
接上篇《49、当当网Scrapy项目实战(二)》 上一篇我们讲解了的Spider与item之间的关系,以及如何使用item,以及使用pipelines管道进行数据下载的操作,本篇我们来讲解Scrapy的多页面下载如何实现。 一、多页面下载原理分…...
wordpress后台更新后 前端没变化的解决方法
使用siteground主机的wordpress网站,会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后,网站没有变化的情况。 不熟悉siteground主机的新手,遇到这个问题,就很抓狂,明明是哪都没操作错误&#x…...
rknn优化教程(二)
文章目录 1. 前述2. 三方库的封装2.1 xrepo中的库2.2 xrepo之外的库2.2.1 opencv2.2.2 rknnrt2.2.3 spdlog 3. rknn_engine库 1. 前述 OK,开始写第二篇的内容了。这篇博客主要能写一下: 如何给一些三方库按照xmake方式进行封装,供调用如何按…...
渗透实战PortSwigger靶场-XSS Lab 14:大多数标签和属性被阻止
<script>标签被拦截 我们需要把全部可用的 tag 和 event 进行暴力破解 XSS cheat sheet: https://portswigger.net/web-security/cross-site-scripting/cheat-sheet 通过爆破发现body可以用 再把全部 events 放进去爆破 这些 event 全部可用 <body onres…...
c++ 面试题(1)-----深度优先搜索(DFS)实现
操作系统:ubuntu22.04 IDE:Visual Studio Code 编程语言:C11 题目描述 地上有一个 m 行 n 列的方格,从坐标 [0,0] 起始。一个机器人可以从某一格移动到上下左右四个格子,但不能进入行坐标和列坐标的数位之和大于 k 的格子。 例…...
Robots.txt 文件
什么是robots.txt? robots.txt 是一个位于网站根目录下的文本文件(如:https://example.com/robots.txt),它用于指导网络爬虫(如搜索引擎的蜘蛛程序)如何抓取该网站的内容。这个文件遵循 Robots…...
鱼香ros docker配置镜像报错:https://registry-1.docker.io/v2/
使用鱼香ros一件安装docker时的https://registry-1.docker.io/v2/问题 一键安装指令 wget http://fishros.com/install -O fishros && . fishros出现问题:docker pull 失败 网络不同,需要使用镜像源 按照如下步骤操作 sudo vi /etc/docker/dae…...
3403. 从盒子中找出字典序最大的字符串 I
3403. 从盒子中找出字典序最大的字符串 I 题目链接:3403. 从盒子中找出字典序最大的字符串 I 代码如下: class Solution { public:string answerString(string word, int numFriends) {if (numFriends 1) {return word;}string res;for (int i 0;i &…...
2023赣州旅游投资集团
单选题 1.“不登高山,不知天之高也;不临深溪,不知地之厚也。”这句话说明_____。 A、人的意识具有创造性 B、人的认识是独立于实践之外的 C、实践在认识过程中具有决定作用 D、人的一切知识都是从直接经验中获得的 参考答案: C 本题解…...
在web-view 加载的本地及远程HTML中调用uniapp的API及网页和vue页面是如何通讯的?
uni-app 中 Web-view 与 Vue 页面的通讯机制详解 一、Web-view 简介 Web-view 是 uni-app 提供的一个重要组件,用于在原生应用中加载 HTML 页面: 支持加载本地 HTML 文件支持加载远程 HTML 页面实现 Web 与原生的双向通讯可用于嵌入第三方网页或 H5 应…...
R语言速释制剂QBD解决方案之三
本文是《Quality by Design for ANDAs: An Example for Immediate-Release Dosage Forms》第一个处方的R语言解决方案。 第一个处方研究评估原料药粒径分布、MCC/Lactose比例、崩解剂用量对制剂CQAs的影响。 第二处方研究用于理解颗粒外加硬脂酸镁和滑石粉对片剂质量和可生产…...
