一、程序框图

KFileMonitor开发文档 - 图2

本FileMonitor文件监控软件总体上可以分为主线程(主界面布局显示,用户操作数据获取,监控数据流显示)及多个次线程(监控功能函数)。

KFileMonitor主界面类,负责主界面布局显示,配置文件读取与设置,最小化托盘与通知管理,信号与槽的连接,创建子线程并发送监控开始信号。

总体界面介绍KFileMonitor开发文档 - 图3

KFileMonitor采用了三个垂直布局器和一个水平布局器,包含了三个KDirectoryBar类,一个KSeleBar类,一个KCheckBar类,一个KFunctionBar类,一个KTableView类。

A1区域为文件path获取区域(KDirectoryBar),本项目可以同时监控三个独立的盘符内文件夹。文件夹地址可以在textline内手动输入,或者点击“. . .”按钮,选择文件夹。

KFileMonitor开发文档 - 图4

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区域新监控内容将不显示该项内容。

KFileMonitor开发文档 - 图5

A3区域为功能区(KFunctionBar),包含四个按键:start watch(开始监听)、exit watch(结束监听)、save log(保存log)、clear log(清除 log)。

  • start watch:当按下该button后,主线程发出信号,通知三个子线程开始监听。同时按钮变成蓝色,非可按下状态,提示用户正在监听状态。KFileMonitor开发文档 - 图6
  • exit watch:当按下该button后,停止监听,start watch按钮重新变成灰色可按下状态。
  • save log:当按下该按钮后,存储在数据库中的日志信息,将会存储为csv格式表格(可更改保存文件名)。

KFileMonitor开发文档 - 图7

  • clear log:当按下该按钮后,存储在数据库中的日志信息会被清空,tableview显示空。

KFileMonitor开发文档 - 图8

A4 区域为显示及搜索log区域(KTableView)。显示信息为id,date,time,operation,attribute,size,directory。上方的搜索框内可输入date,time,operation,attribute,size,directory进行搜索。当搜索内容为空时,点击search显示所有数据。

KFileMonitor开发文档 - 图9

其它内容

最小化托盘:

点击上方”X”按钮时,弹出对话框,点击hide最小化托盘,点击exit退出程序。

KFileMonitor开发文档 - 图10

当程序最小化期间,有文件监控事件发生时,小图标会闪烁提示,右键点击小图标 可以选择显示程序主界面,退出程序,或者忽略消息。

KFileMonitor开发文档 - 图11KFileMonitor开发文档 - 图12

二、程序亮点

1. 数据管理

单例模式全局数据管理类,进行全局数据的管理,程序日志信息保存至Sql数据库中。

2. 配置信息

该程序支持上次的配置信息,下次打开软件之后自动按照上次的结果配置

3. 消息提醒与忽略

程序最小化运行时支持消息的提醒与忽略

4. 支持日志信息导出csv格式保存

点击save log 按钮可以保存信息

5. 多线程运行

三个监控都在子线程运行,数据监控与界面显示相互独立,通过全局数据与主线程联系,同时使用了线程锁,保证了线程安全。

  1. //子线程运行
  2. m_pThread = new QThread;
  3. m_fileWatcher = new KFileWatcher;
  4. m_fileWatcher->moveToThread(m_pThread);
  5. m_pThread2 = new QThread;
  6. m_fileWatcher2 = new KFileWatcher;
  7. m_fileWatcher2->moveToThread(m_pThread2);
  8. m_pThread3 = new QThread;
  9. m_fileWatcher3 = new KFileWatcher;
  10. m_fileWatcher3->moveToThread(m_pThread3);
  1. //线程锁,限制访问数据
  2. void KGlobalData::setLogText(QString log)
  3. {
  4. m_mutex.lock();
  5. m_log = log;
  6. m_mutex.unlock();
  7. }

6. 数据转换(GBK编码,“\”替换”/“)

Qt不支持GBK编码,当文件夹目录存在GBK编码的中文文件时,会显示乱码。

  1. std::string KFileWatcher::GbkToUtf8(const char* src_str)
  2. {
  3. int len = MultiByteToWideChar(CP_ACP, 0, src_str, -1, NULL, 0);
  4. wchar_t* wstr = new wchar_t[len + 1];
  5. memset(wstr, 0, len + 1);
  6. MultiByteToWideChar(CP_ACP, 0, src_str, -1, wstr, len);
  7. len = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, NULL, 0, NULL, NULL);
  8. char* str = new char[len + 1];
  9. memset(str, 0, len + 1);
  10. WideCharToMultiByte(CP_UTF8, 0, wstr, -1, str, len, NULL, NULL);
  11. std::string strTemp = str;
  12. if (wstr) delete[] wstr;
  13. if (str) delete[] str;
  14. wstr = nullptr;
  15. str = nullptr;
  16. return strTemp;
  17. }
  1. for (char s : m_filename)
  2. {
  3. if (s == '\\')
  4. {
  5. utf8FileName += '/';
  6. }
  7. else
  8. {
  9. utf8FileName += s;
  10. }
  11. }

7. 条件过滤

数据存入checkbox之前进行条件过滤。

  1. //ex过滤
  2. QStringList strEx = KGlobalData::getGlobalDataIntance()->getFilterEx().split(" ");
  3. int exSize = strEx.size();
  4. if (KGlobalData::getGlobalDataIntance()->getFilterEx() != "")
  5. {
  6. for (int i = 0; i < exSize; i++)
  7. {
  8. if (strEx[i] == Operation || strEx[i] + " " == Directory || strEx[i] + " " == fileName || strEx[i] == Attribute)
  9. {
  10. return ;
  11. }
  12. }
  13. }
  14. //in过滤
  15. QStringList strIn = KGlobalData::getGlobalDataIntance()->getFilterIn().split(" ");
  16. int inSize = strIn.size();
  17. if (KGlobalData::getGlobalDataIntance()->getFilterIn() != "")
  18. {
  19. for (int j = 0; j < inSize; j++)
  20. {
  21. if (strIn[j] == Operation || strIn[j] + " " == Directory || strIn[j] + " " == fileName || strIn[j] == Attribute)
  22. {
  23. break;
  24. }
  25. else
  26. {
  27. return;
  28. }
  29. }
  30. }