目录监控功能主要用在系统间数据迁移时观察缓存目录文件变化的场景,结合文件类型检测、病毒检测、安全文件传输等功能可以构建一个完整的系统文件安全入出的解决方案。该功能有多种实现方式,下面我们介绍两种不同方式来实现该功能。
通过ReadDirectoryChangesW实现目录监控
ReadDirectoryChangesW是Windows专门用于监控文件系统变化的一个系统API,我们通过调用该系统API可以实现目录变化的监控。
参考如下:
ReadDirectoryChangesW 函数 (winbase.h) - Win32 apps | Microsoft Learn
下面具体说明一下如何实现:
目录监控功能控制
在SystemPanel的菜单资源编辑器中添加新的菜单项
修改菜单变量名,添加菜单事件处理函数
在目录监控控制菜单处理函数中添加如下代码:
//目录监控控制
#include <thread>
#include <future>
#include <functional>
#include <queue>
HANDLE m_hDirectory;//需要监控目录的句柄
queue<tuple<string, string, int>> dirChangeQueue;//目录变化数据队列
#define SYS_ALLOC_BUF 1024*128
future<void> t_rdm;//检测目录文件改变的后台过程futrue
future<void> t_redm;//处理目录文件改变的后台过程futrue
void SystemPanel::Onm_DirMonAPISelected(wxCommandEvent& event)
{
if(m_hDirectory!=NULL)
{
int ret=wxMessageBox(_("系统有正在监控的目录,是否停止?"),_("目录监控提示"),wxYES_NO,this);
if(ret==wxYES)
{
cout<<"正在停止目录监控"<<endl;
if(m_hDirectory!=NULL)
{
CloseHandle(m_hDirectory);
m_hDirectory=NULL;
}
//监控前清空监控列表
if(m_FileList->GetItemCount()!=0)
m_FileList->DeleteAllItems();
}
else if(ret==wxNO)
{
m_DirMonAPI->Check(true);
return;
}
else
{
m_DirMonAPI->Check(true);
return;
}
}
else
{
wxString pathName=wxDirSelector(_("请选择要监控的目录!"), "",
wxDD_DEFAULT_STYLE | wxDD_DIR_MUST_EXIST);
if ( pathName.empty() )
{
m_DirMonAPI->Check(false);
return;
}
//监控前清空监控列表
if(m_FileList->GetItemCount()!=0)
m_FileList->DeleteAllItems();
//监控前获取所有监控目标
AdjustPrivileges();//提升权限,解决特殊文件访问导致的软件崩溃
for(auto &p:std::filesystem::recursive_directory_iterator(pathName.ToStdString()))
{
std::cout << p.path() << endl;
if(m_FileList->FindItem(-1,p.path().wstring(),false)!=wxNOT_FOUND)
continue;
auto indexItem = m_FileList->InsertItem(m_FileList->GetItemCount(),_(""));
m_FileList->SetItem(indexItem, 0, (p.path().wstring()));
if(!std::filesystem::is_directory(p))
m_FileList->SetItem(indexItem, 1,to_string(std::filesystem::file_size(p)));
else
m_FileList->SetItem(indexItem, 1,_("Dir"));
m_FileList->SetItem(indexItem, 2,p.path().extension().wstring() );
}
//异步执行目录监控
t_rdm=async(std::launch::async,bind(&DoDirMonitor,this,pathName));
cout<<"当前正在监控的目录是: "+pathName<<endl;
}
}
监控目录消息
由于目录变化消息可能很多,为了防止在处理很多目录变化时可能会丢失目录变化消息的问题发生,我们采用异步的方式来运行如下目录消息监控代码:
void SystemPanel::D