一、程序框图
本FileMonitor文件监控软件总体上可以分为主线程(主界面布局显示,用户操作数据获取,监控数据流显示)及多个次线程(监控功能函数)。
KFileMonitor主界面类,负责主界面布局显示,配置文件读取与设置,最小化托盘与通知管理,信号与槽的连接,创建子线程并发送监控开始信号。
总体界面介绍
KFileMonitor采用了三个垂直布局器和一个水平布局器,包含了三个KDirectoryBar类,一个KSeleBar类,一个KCheckBar类,一个KFunctionBar类,一个KTableView类。
A1区域为文件path获取区域(KDirectoryBar),本项目可以同时监控三个独立的盘符内文件夹。文件夹地址可以在textline内手动输入,或者点击“. . .”按钮,选择文件夹。
A2区域为监控属性区域,分为上下两部分,过滤器(KSeleBar)及监控属性选择(KCheckBar)。过滤器的include only为“仅监控”选项,内部可以填入某个文件的完整地址,文件全名(例如:XXXX. txt)和文件类型(例如: pptx)。支持填入多个选项,使用空格符号隔开(例如:C:/Users/42436/Desktop/test2 123.txt pptx readme.md)。过滤器的exclude all为“全部排除”选项, 内部可以填入某个文件的完整地址,文件全名(例如:XXXX. txt)和文件类型(例如: pptx)。支持填入多个选项,使用空格符号隔开(例如:C:/Users/42436/Desktop/test2 123.txt pptx readme.md)。exclude all 权限大于include only,当相同内容分别被填入时,会被排除该项内容的监控。
A2的监控属性选择区域采用了checkbox,可以选择监控文件更改的属性。其内容分别为:file name(文件名更改)、dir name(路径名更改)、file size(文件大小的更改)、attribute(文件属性的更改)、last write(上次写入)、last access(上次读取)、creation(新建文件),watch subdir(监控子文件夹)。当file size和attribute非选中时,A4区域新监控内容将不显示该项内容。
A3区域为功能区(KFunctionBar),包含四个按键:start watch(开始监听)、exit watch(结束监听)、save log(保存log)、clear log(清除 log)。
- start watch:当按下该button后,主线程发出信号,通知三个子线程开始监听。同时按钮变成蓝色,非可按下状态,提示用户正在监听状态。
- exit watch:当按下该button后,停止监听,start watch按钮重新变成灰色可按下状态。
- save log:当按下该按钮后,存储在数据库中的日志信息,将会存储为csv格式表格(可更改保存文件名)。
- clear log:当按下该按钮后,存储在数据库中的日志信息会被清空,tableview显示空。
A4 区域为显示及搜索log区域(KTableView)。显示信息为id,date,time,operation,attribute,size,directory。上方的搜索框内可输入date,time,operation,attribute,size,directory进行搜索。当搜索内容为空时,点击search显示所有数据。
其它内容
最小化托盘:
点击上方”X”按钮时,弹出对话框,点击hide最小化托盘,点击exit退出程序。
当程序最小化期间,有文件监控事件发生时,小图标会闪烁提示,右键点击小图标 可以选择显示程序主界面,退出程序,或者忽略消息。
二、程序亮点
1. 数据管理
单例模式全局数据管理类,进行全局数据的管理,程序日志信息保存至Sql数据库中。
2. 配置信息
该程序支持上次的配置信息,下次打开软件之后自动按照上次的结果配置
3. 消息提醒与忽略
程序最小化运行时支持消息的提醒与忽略
4. 支持日志信息导出csv格式保存
点击save log 按钮可以保存信息
5. 多线程运行
三个监控都在子线程运行,数据监控与界面显示相互独立,通过全局数据与主线程联系,同时使用了线程锁,保证了线程安全。
//子线程运行
m_pThread = new QThread;
m_fileWatcher = new KFileWatcher;
m_fileWatcher->moveToThread(m_pThread);
m_pThread2 = new QThread;
m_fileWatcher2 = new KFileWatcher;
m_fileWatcher2->moveToThread(m_pThread2);
m_pThread3 = new QThread;
m_fileWatcher3 = new KFileWatcher;
m_fileWatcher3->moveToThread(m_pThread3);
//线程锁,限制访问数据
void KGlobalData::setLogText(QString log)
{
m_mutex.lock();
m_log = log;
m_mutex.unlock();
}
6. 数据转换(GBK编码,“\”替换”/“)
Qt不支持GBK编码,当文件夹目录存在GBK编码的中文文件时,会显示乱码。
std::string KFileWatcher::GbkToUtf8(const char* src_str)
{
int len = MultiByteToWideChar(CP_ACP, 0, src_str, -1, NULL, 0);
wchar_t* wstr = new wchar_t[len + 1];
memset(wstr, 0, len + 1);
MultiByteToWideChar(CP_ACP, 0, src_str, -1, wstr, len);
len = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, NULL, 0, NULL, NULL);
char* str = new char[len + 1];
memset(str, 0, len + 1);
WideCharToMultiByte(CP_UTF8, 0, wstr, -1, str, len, NULL, NULL);
std::string strTemp = str;
if (wstr) delete[] wstr;
if (str) delete[] str;
wstr = nullptr;
str = nullptr;
return strTemp;
}
for (char s : m_filename)
{
if (s == '\\')
{
utf8FileName += '/';
}
else
{
utf8FileName += s;
}
}
7. 条件过滤
数据存入checkbox之前进行条件过滤。
//ex过滤
QStringList strEx = KGlobalData::getGlobalDataIntance()->getFilterEx().split(" ");
int exSize = strEx.size();
if (KGlobalData::getGlobalDataIntance()->getFilterEx() != "")
{
for (int i = 0; i < exSize; i++)
{
if (strEx[i] == Operation || strEx[i] + " " == Directory || strEx[i] + " " == fileName || strEx[i] == Attribute)
{
return ;
}
}
}
//in过滤
QStringList strIn = KGlobalData::getGlobalDataIntance()->getFilterIn().split(" ");
int inSize = strIn.size();
if (KGlobalData::getGlobalDataIntance()->getFilterIn() != "")
{
for (int j = 0; j < inSize; j++)
{
if (strIn[j] == Operation || strIn[j] + " " == Directory || strIn[j] + " " == fileName || strIn[j] == Attribute)
{
break;
}
else
{
return;
}
}
}