当前位置: 首页 > news >正文

文件系统事件监听

文件系统事件和网络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事件一样&#xff0c;也可以通过epoll或者IOCP 事件管理器统一调度&#xff0c;当所监控的文件或文件夹发生了增删改的事件时&#xff0c;就会触发事件回调&#xff0c;进行事件处理。很常见的应用&#xff0c;如配置文件立即生效功能&#xff0c;就可以通…...

探秘HTTPS:如何通过SSL/TLS保证网络通信安全

目录 引言 详解HTTPS加密实现机制 SSL/TLS工作原理 结论 引言 随着网络安全威胁的日益增加&#xff0c;HTTPS通过SSL&#xff08;Secure Sockets Layer&#xff09;和TLS&#xff08;Transport Layer Security&#xff09;协议提供的加密技术变得至关重要。这些技术保证了用…...

Java算法之动态规划

Java算法之动态规划 前言 ​ 最近这一段时间一直在刷算法题&#xff0c;基本上一有时间就会做一两道&#xff0c;这两天做了几道动态规划的问题&#xff0c;动态规划之前一直是我比较头疼的一个问题&#xff0c;感觉好复杂&#xff0c;一遇到这样的问题就想跳过&#xff0c;昨…...

C++从零开始的打怪升级之路(day47)

这是关于一个普通双非本科大一学生的C的学习记录贴 在此前&#xff0c;我学了一点点C语言还有简单的数据结构&#xff0c;如果有小伙伴想和我一起学习的&#xff0c;可以私信我交流分享学习资料 那么开启正题 今天分享的是关于set和map的知识点 1.关联式容器 在前面&#…...

香橙派AIpro开发板开箱测评

2023年12月&#xff0c;香橙派联合华为发布了基于昇腾的Orange Pi AIpro开发板&#xff0c;提供8/20TOPS澎湃算力&#xff0c;能覆盖生态开发板者的主流应用场景&#xff0c;让用户实践各种创新场景&#xff0c;并为其提供配套的软硬件。香橙派AIpro开发板一经发布便吸引了众多…...

ISP基础概述

原文来自ISP 和摄像头基本知识 本文主要介绍ISP&#xff0c;以供读者能够理解该技术的定义、原理、应用。 &#x1f3ac;个人简介&#xff1a;一个全栈工程师的升级之路&#xff01; &#x1f4cb;个人专栏&#xff1a;计算机杂记 &#x1f380;CSDN主页 发狂的小花 &#x1f3…...

C++第一弹---C++入门(上)

✨个人主页&#xff1a; 熬夜学编程的小林 &#x1f497;系列专栏&#xff1a; 【C语言详解】 【数据结构详解】 【C详解】 C入门 1、C关键字(C98) 2、命名空间 2.1、命名空间定义 2.2、命名空间使用 3、C输入&输出 4、缺省参数 4.1、缺省参数概念 4.2、缺省参…...

VScode格式化快捷键

vscode格式化代码快捷键 如何使用快捷键格式化代码。使用Java的格式去设置&#xff0c;发现不起作用。 在这里记录一下&#xff1a; 在Windows中&#xff0c;vscode格式化代码快捷键是“ShiftAltF”&#xff1b; 在Mac中&#xff0c;vscode格式化代码快捷键是“ShiftOption…...

HCIP---IS-IS协议

文章目录 前言一、pandas是什么&#xff1f;二、使用步骤 1.引入库2.读入数据总结 一.IS-IS协议概述 IS-IS是一种基于链路状态的内部网关协议&#xff08;IGP&#xff09;&#xff0c;它使用最短路径优先算法&#xff08;SPF或Dijkstra&#xff09;进行路由计算。这种协议在自治…...

突破编程_C++_设计模式(组合模式)

1 组合模式的基本概念 C中的组合模式是一种对象结构型模式&#xff0c;它将多个对象组合成树形结构&#xff0c;以表示具有整体-部分关系的层次结构。在这个模式中&#xff0c;对单个对象&#xff08;叶子对象&#xff09;与组合对象&#xff08;容器对象&#xff09;的使用具…...

010Editor汉化版+下载+注册码+模板bug

项目场景&#xff1a; 这天我想使用我的不知名的一个破解版本的010Edit来查看一个EXE程序&#xff0c;并想使用模板功能&#xff0c;但是发现没有该模板还无法下载最新模板 问题描述 010Edit联网后需要注册码&#xff1a; 010 Editor 激活码生成器 使用方法 参照教程使用0…...

js【详解】BOM

浏览器对象模型 &#xff08;Browser obiect Mode 简称 BOM&#xff09; 浏览器对象即 window&#xff0c;调用window对象的属性和方法时&#xff0c;可以省略window window 常用的属性 Navigator 常用于获取浏览器的信息 navigator.userAgent;火狐浏览器范例&#xff1a; “…...

Leetcode 3077. Maximum Strength of K Disjoint Subarrays

Leetcode 3077. Maximum Strength of K Disjoint Subarrays 1. 解题思路 1. 朴素思路2. 算法优化 2. 代码实现 题目链接&#xff1a;3077. Maximum Strength of K Disjoint Subarrays 1. 解题思路 这道题很惭愧没有搞定&#xff0c;思路上出现了差错&#xff0c;导致一直没能…...

【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区块链开发者大会。作为比特币生态的领军项目&#xff0c;Babylon积极参与全球区块链领域的交流与合作&#xff0c;此次出席大会将为其提供一个展示项目进展、交流技术与创新思路的重要平台。B…...

如何学习、上手点云算法(三):用VsCode、Visual Studio来debug基于PCL、Open3D的代码

写在前面 本文内容 以PCL 1.14.0&#xff0c;Open3D0.14.1为例&#xff0c;对基于PCL、Open3D开发的代码进行源码debug&#xff1b; 如何学习、上手点云算法系列&#xff1a; 如何学习、上手点云算法(一)&#xff1a;点云基础 如何学习、上手点云算法(二)&#xff1a;点云处理相…...

【干货】alzet渗透泵操作说明

alzet渗透泵是一款小型、可植入式的胶囊渗透泵产品&#xff0c;此产品由于其独特的渗透原理&#xff0c;深受广大科研人员的喜爱。该泵可适用于小鼠、大鼠及其他实验动物的研究&#xff0c;并且alzet渗透泵可减轻科研人员夜间及周末给药的困扰。alzet渗透泵无需外部连接或频繁处…...

CVPR 2022 Oral | Bailando: 基于编舞记忆和Actor-Critic GPT的3D舞蹈生成

目录 测试结果&#xff1a; 02 提出的方法 测试结果&#xff1a; 预测有3个步骤&#xff0c;速度比较慢 02 提出的方法 1. 针对舞蹈序列的VQ-VAE和编舞记忆 与之前的方法不同&#xff0c;我们不学习从音频特征到 3D 关键点序列的连续域的直接映射。相反&#xff0c;我们先让…...

解读电影级视频生成模型 MovieFactory

Diffusion Models视频生成-博客汇总 前言:MovieFactory是第一个全自动电影生成模型,可以根据用户输入的文本信息自动扩写剧本,并生成电影级视频。其中针对预训练的图像生成模型与视频模型之间的gap提出了微调方法非常值得借鉴。这篇博客详细解读一下这篇论文《MovieFactory:…...

【Python从入门到进阶】50、当当网Scrapy项目实战(三)

接上篇《49、当当网Scrapy项目实战&#xff08;二&#xff09;》 上一篇我们讲解了的Spider与item之间的关系&#xff0c;以及如何使用item&#xff0c;以及使用pipelines管道进行数据下载的操作&#xff0c;本篇我们来讲解Scrapy的多页面下载如何实现。 一、多页面下载原理分…...

conda相比python好处

Conda 作为 Python 的环境和包管理工具&#xff0c;相比原生 Python 生态&#xff08;如 pip 虚拟环境&#xff09;有许多独特优势&#xff0c;尤其在多项目管理、依赖处理和跨平台兼容性等方面表现更优。以下是 Conda 的核心好处&#xff1a; 一、一站式环境管理&#xff1a…...

【WiFi帧结构】

文章目录 帧结构MAC头部管理帧 帧结构 Wi-Fi的帧分为三部分组成&#xff1a;MAC头部frame bodyFCS&#xff0c;其中MAC是固定格式的&#xff0c;frame body是可变长度。 MAC头部有frame control&#xff0c;duration&#xff0c;address1&#xff0c;address2&#xff0c;addre…...

React Native在HarmonyOS 5.0阅读类应用开发中的实践

一、技术选型背景 随着HarmonyOS 5.0对Web兼容层的增强&#xff0c;React Native作为跨平台框架可通过重新编译ArkTS组件实现85%以上的代码复用率。阅读类应用具有UI复杂度低、数据流清晰的特点。 二、核心实现方案 1. 环境配置 &#xff08;1&#xff09;使用React Native…...

MVC 数据库

MVC 数据库 引言 在软件开发领域,Model-View-Controller(MVC)是一种流行的软件架构模式,它将应用程序分为三个核心组件:模型(Model)、视图(View)和控制器(Controller)。这种模式有助于提高代码的可维护性和可扩展性。本文将深入探讨MVC架构与数据库之间的关系,以…...

大模型多显卡多服务器并行计算方法与实践指南

一、分布式训练概述 大规模语言模型的训练通常需要分布式计算技术,以解决单机资源不足的问题。分布式训练主要分为两种模式: 数据并行:将数据分片到不同设备,每个设备拥有完整的模型副本 模型并行:将模型分割到不同设备,每个设备处理部分模型计算 现代大模型训练通常结合…...

ip子接口配置及删除

配置永久生效的子接口&#xff0c;2个IP 都可以登录你这一台服务器。重启不失效。 永久的 [应用] vi /etc/sysconfig/network-scripts/ifcfg-eth0修改文件内内容 TYPE"Ethernet" BOOTPROTO"none" NAME"eth0" DEVICE"eth0" ONBOOT&q…...

Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信

文章目录 Linux C语言网络编程详细入门教程&#xff1a;如何一步步实现TCP服务端与客户端通信前言一、网络通信基础概念二、服务端与客户端的完整流程图解三、每一步的详细讲解和代码示例1. 创建Socket&#xff08;服务端和客户端都要&#xff09;2. 绑定本地地址和端口&#x…...

安宝特案例丨Vuzix AR智能眼镜集成专业软件,助力卢森堡医院药房转型,赢得辉瑞创新奖

在Vuzix M400 AR智能眼镜的助力下&#xff0c;卢森堡罗伯特舒曼医院&#xff08;the Robert Schuman Hospitals, HRS&#xff09;凭借在无菌制剂生产流程中引入增强现实技术&#xff08;AR&#xff09;创新项目&#xff0c;荣获了2024年6月7日由卢森堡医院药剂师协会&#xff0…...

根目录0xa0属性对应的Ntfs!_SCB中的FileObject是什么时候被建立的----NTFS源代码分析--重要

根目录0xa0属性对应的Ntfs!_SCB中的FileObject是什么时候被建立的 第一部分&#xff1a; 0: kd> g Breakpoint 9 hit Ntfs!ReadIndexBuffer: f7173886 55 push ebp 0: kd> kc # 00 Ntfs!ReadIndexBuffer 01 Ntfs!FindFirstIndexEntry 02 Ntfs!NtfsUpda…...

Kubernetes 节点自动伸缩(Cluster Autoscaler)原理与实践

在 Kubernetes 集群中&#xff0c;如何在保障应用高可用的同时有效地管理资源&#xff0c;一直是运维人员和开发者关注的重点。随着微服务架构的普及&#xff0c;集群内各个服务的负载波动日趋明显&#xff0c;传统的手动扩缩容方式已无法满足实时性和弹性需求。 Cluster Auto…...