可以实现对本地文件的 增、删、改、重命名等操作的监控,通过登录远程文件监控系统,获取一段时间内本地文件的变化情况。
系统功能图如下:
流程图如下:
二、本地文件监控程序的实现(C++)
调用 windows api 监控本地文件操作,将对应的文件操作上传到远程数据库端。
#include <Windows.h> #include <string> #include <iostream> #include <iomanip> #include <tchar.h> #include <winsock.h> #include "include/mysql.h" #include <ctime> #include <thread> #pragma comment(lib,"lib/libmysql.lib") #pragma comment(lib,"lib/mysqlclient.lib") using namespace std; /* 通过CreateFile函数打开监控目录,获取监控目录的句柄 API函数ReadDirecotryChangesW,实现文件监控操作 */ //字符串替换(全部) string replace(string& base, string src, string dst) { int pos = 0, srclen = src.size(), dstlen = dst.size(); while ((pos = base.find(src, pos)) != string::npos) { base.replace(pos, srclen, dst); pos += dstlen; } return base; } //void DirectoryMonitoring(); void DirectoryMonitoring(const TCHAR * disk,MYSQL &mysql) { //cout << __FUNCTION__ << " is called." << endl; //__FUNCTION__,当前被调用的函数名 string sql; ///mysql下面 DWORD cbBytes; //Double Word Windows.h中 char file_Name[MAX_PATH]; //设置文件名 char file_Name2[MAX_PATH]; //设置文件重命名后的名字 char notify[1024]; int count = 0; //文件操作次数 TCHAR *dir =(TCHAR *) _T(disk); //_T 确保编码的兼容性,磁盘名 //调用CreateFile(Win Api)来获得指向一个物理硬盘的句柄,CreateFile函数打开监控目录,获取监控目录的句柄。 HANDLE dirHandle = CreateFile(dir, GENERIC_READ | GENERIC_WRITE | FILE_LIST_DIRECTORY, //访问模式对设备可以读写数据 FILE_SHARE_READ | FILE_SHARE_WRITE, //共享模式可读可写 NULL, //文件的安全特性,无 OPEN_EXISTING, //文件必须已经存在,若不存在函数返回失败 FILE_FLAG_BACKUP_SEMANTICS, //文件属性 NULL); //用于复制文件句柄 if (dirHandle == INVALID_HANDLE_VALUE) //是否成功 { cout << "error" + GetLastError() << endl; } memset(notify, 0, strlen(notify)); //给notify赋值为0,即清空数组 FILE_NOTIFY_INFORMATION *pnotify = (FILE_NOTIFY_INFORMATION*)notify; //结构体FILE_NOTIFY_INFORMATION,存储文件操作信息其action属性 cout << "正在监视文件" << endl; while (true) { if (ReadDirectoryChangesW(dirHandle, ¬ify, 1024, true, //对目录进行监视的句柄;一个指向FILE_NOTIFY_INFORMATION结构体的缓冲区,其中可以将获取的数据结果将其返回;lpBuffer的缓冲区的大小值,以字节为单位;是否监视子目录. FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_SIZE, //对文件过滤的方式和标准 &cbBytes, NULL, NULL)) //将接收的字节数转入lpBuffer参数 { //宽字节转换为多字节 if (pnotify->FileName) { memset(file_Name, 0, strlen(file_Name)); WideCharToMultiByte(CP_ACP, 0, pnotify->FileName, pnotify->FileNameLength / 2, file_Name, 99, NULL, NULL); } //重命名的文件名 if (pnotify->NextEntryOffset != 0 && (pnotify->FileNameLength > 0 && pnotify->FileNameLength < MAX_PATH)) { PFILE_NOTIFY_INFORMATION p = (PFILE_NOTIFY_INFORMATION)((char*)pnotify + pnotify->NextEntryOffset); memset(file_Name2, 0, sizeof(file_Name2)); WideCharToMultiByte(CP_ACP, 0, p->FileName, p->FileNameLength / 2, file_Name2, 99, NULL, NULL); } string str=file_Name; str = replace(str, "\\", "http://www.likecs.com/"); str = dir+str; string str2=file_Name2; str2 = replace(str2, "\\", "http://www.likecs.com/"); str2 = dir+str2; string link = "-->"; //设置类型过滤器,监听文件创建、更改、删除、重命名等 switch (pnotify->Action) { case FILE_ACTION_ADDED: //添加文件 count++; cout << count << setw(5) << "File Add:" << setw(5) << file_Name << endl; sql = "begin;"; mysql_query(&mysql, sql.c_str()); sql = "insert into file_info(action,name)\ values (\"File Added\",\""+str+"\");"; if (mysql_query(&mysql, sql.c_str())) { cout << "line: " << __LINE__ << ";" << mysql_error(&mysql) << mysql_errno(&mysql) << endl; } sql = "commit;"; mysql_query(&mysql, sql.c_str()); break; case FILE_ACTION_MODIFIED: //修改文件 cout << "File Modified:" << setw(5) << file_Name << endl; sql = "begin;"; mysql_query(&mysql, sql.c_str()); sql = "insert into file_info(action,name)\ values (\"File Modified\",\"" + str + "\");"; if (mysql_query(&mysql, sql.c_str())) { cout << "line: " << __LINE__ << ";" << mysql_error(&mysql) << mysql_errno(&mysql) << endl; } sql = "commit;"; mysql_query(&mysql, sql.c_str()); break; case FILE_ACTION_REMOVED: //删除文件 count++; cout << count << setw(5) << "File Removed:" << setw(5) << file_Name << endl; sql = "begin;"; mysql_query(&mysql, sql.c_str()); sql = "insert into file_info(action,name)\ values (\"File Deleted\",\"" + str + "\");"; if (mysql_query(&mysql, sql.c_str())) { cout << "line: " << __LINE__ << ";" << mysql_error(&mysql) << mysql_errno(&mysql) << endl; } sql = "commit;"; mysql_query(&mysql, sql.c_str()); break; case FILE_ACTION_RENAMED_OLD_NAME: //重命名 cout << "File Renamed:" << setw(5) << file_Name << "->" << file_Name2 << endl; sql = "begin;"; mysql_query(&mysql, sql.c_str()); sql = "insert into file_info(action,name)\ values (\"File Renamed\",\"" + str+link+str2 + "\");"; if (mysql_query(&mysql, sql.c_str())) { cout << "line: " << __LINE__ << ";" << mysql_error(&mysql) << mysql_errno(&mysql) << endl; } sql = "commit;"; mysql_query(&mysql, sql.c_str()); break; default: cout << "未知命令" << endl; } } } CloseHandle(dirHandle); } int _tmain(int argc, _TCHAR* argv[]) { const TCHAR * disk1 = _T("C://"); const TCHAR * disk2 = _T("D://"); const TCHAR * disk3 = _T("E://"); MYSQL mysql; mysql_init(&mysql); // 连接远程数据库 if (NULL == mysql_real_connect(&mysql, "database_host", "username", "password", "mysql", 3306, NULL, 0)) { cout << __LINE__ << mysql_error(&mysql) << mysql_errno(&mysql) << endl; throw - 1; } //进入数据库hr_1 string sql = "use hr_1;"; if (mysql_query(&mysql, sql.c_str())) { cout << "line: " << __LINE__ << ";" << mysql_error(&mysql) << mysql_errno(&mysql) << endl; throw - 1; } mysql_query(&mysql, "SET NAMES GBK"); //数据库编码格式 thread t1(DirectoryMonitoring, disk1,ref(mysql)); thread t2(DirectoryMonitoring, disk2,ref(mysql)); thread t3(DirectoryMonitoring, disk3,ref(mysql)); t1.join(); t2.join(); t3.join(); return 0; } 三、后端的实现(Java)后端框架:SpringBoot 依赖:mybatis、lombok