一.项目简介:
Linux操作系统中提供了find指令查找指定文件,为了实现在Windows操作系统中实现文件的快搜搜索,利用所学知识实现文件搜索神器,与软件everything工具具有一定的相同功能,即:快速通过汉字,首字母,拼音实现文件的快速搜索。
二.项目需求及环境
(一)需求
- 通过首字母,汉字,拼音实现文件快速搜索。
- 实现搜索关键字的高亮处理。
(二)开发环境
- 编译器 : VS2013 / 控制应用平台
- 编程语言 : C++ / C++11
- 数据库 : sqlite3
sqlite3菜鸟教程:菜鸟教程;
(三)涉及知识点:
- 数据库操作:(sqlite安装,创建数据库,创建表,插入数据,删除数据,创建索引,查询数据 (条件查询、 模糊查询))
- 静态库和动态库:静态库和动态库的制作,动态库和动态的使用。
- 设计模式(单例模式)。
- 多线程。
- 同步机制(互斥量)。
- 日志。
- 汉字与拼音的转换。
三.项目设计。
(一)设计框架:
(二)代码框架:
- 公共模块 : Common.h
- 系统工具模块 : Sysutil.h Sysutil.cpp
- 数据管理模块 : DataManager.h DataManager.cpp
- 扫描管理模块 : ScanManager.h ScanManager.cpp
- 系统驱动模块 : DocFastSearchTool.cpp
(三)文件扫描:
- 文件系统监控是利用系统文件系统的接口可以监控某个目录下的文档变化,有点是效率高实时性强,缺点是监控是实时的,如果在监控程序没有启动期间的,文档的变化无法获取。
- 文件系统扫描是通过系统接口,遍历获取目录下的所有文档跟数据库中的文档进行对比,获取文档变化,优点是监控程序启动前,变化的文档也能对比出来,缺点是性能低实时性不强。
(四)数据持久化:
- 数据持久化我们使用了轻量级的一个数据库sqlite管理,使用sqlite3创建一张表。
(五)中间逻辑层:
- 模糊匹配:
利用数据库中like语句进行模糊匹配搜索。 - 拼音全拼搜索:
存储时将文件名转换成一个拼音全拼存在数据库表的doc_name_pinyin字段中,搜索时也将关键字转换成拼音,然后使用数据库的模糊匹配搜索。 - 拼音首字母搜索:
存储时将文件名转换成一个拼音首字母存在数据库表的doc_name_initials字段中,搜索时也将关键字转换成拼音首字母,然后使用数据库的模糊匹配搜索。 - 高亮处理:
亮处理需要对搜索出的关键字高亮标记处理,如果是直接的模糊匹配,比较简单,就是一个子串匹配,但是拼音全拼搜索和首字母搜索需要使用一套逻辑算法来处理。
四.项目实现
(一)系统工具模块的实现:
- Sysutil.h文件
//界面模块
#define WIDTH 120
#define HEIGHT 30
void SetCurPos(int x, int y); //x 带表界面的行 y 代表界面的列
void HideCursor();
void DrawCol(int x, int y);
void DrawRow(int x, int y);
void DrawFrame(char *title);
void DrawMenu();
void SystemEnd();
/
//获取文件个数
size_t GetFileCount(const string &path);
//目录监控函数
bool DirectoryWatch(const string &path);
//系统功能函数模块
void DirectoryList(const string &path, vector<string> &subfile, vector<string> &subdir);
// 汉字转拼音全拼
/* CSDN:http://blog.csdn.net/csnd_ayo */
string ChineseConvertPinYinAllSpell(const string& dest_chinese);
// 汉字转拼音首字母
string ChineseConvertPinYinInitials(const string& name);
// 颜色高亮显示一段字符串
void ColourPrintf(const string &str);
- 目录扫描
/目录扫描
extern size_t g_FileCount;
extern size_t g_ScanCount;
size_t GetFileCount(const string &path)
{
string _path = path + "\\" + "*.*";
struct _finddata_t fileAttri;
long handle = _findfirst(_path.c_str(), &fileAttri);
if(handle == -1)
return 0;
do
{
if(fileAttri.name[0] == '.')
continue;
g_ScanCount++;
if(fileAttri.attrib & _A_SUBDIR)
GetFileCount(path + "\\" + fileAttri.name);
}while(_findnext(handle, &fileAttri) == 0);
return g_ScanCount;
}
bool DirectoryWatch(const string &path)
{
size_t file_count = GetFileCount(path);
return file_count != g_FileCount;
}
void DirectoryList(const string &path, vector<string> &subfile, vector<string> &subdir)
{
//"E:\\Users\\Documents\\计算机专业课件\\*.*";
string _path = path;
_path += "\\*.*"; //通配符 * ?%
struct _finddata_t file;
long handle = _findfirst(_path.c_str(), &file);
if(handle == -1)
{
perror("_findfirst");
return;
}
do
{
if(file.name[0] == '.')
continue;
//_A_SUBDIR
//是一个文件夹
if(file.attrib & _A_SUBDIR)
subdir.push_back(file.name);
else
subfile.push_back(file.name);
}while(_findnext(handle, &file) == 0);
- 界面模块
#include"Sysutil.h"
//设置光标位置
void SetCurPos(int x, int y)
{
HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
COORD pos = {
y, x};
SetConsoleCursorPosition(handle, pos);
}
//隐藏光标
void HideCursor()
{
HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_CURSOR_INFO cursor_info = {
100, 0};
SetConsoleCursorInfo(handle, &cursor_info);
}
//画列 |
void DrawCol(int x, int y)
{
for(int i=0; i<HEIGHT; ++i)
{
SetCurPos(x+i, y);
printf("|");
}
}
//画行 -
void DrawRow(int x, int y)
{
for(int i=0; i<WIDTH-4; ++i)
{
SetCurPos(x, y+i);
printf("—");
}
}
void SystemEnd()
{
SetCurPos(HEIGHT-1, (WIDTH-4-strlen("请按任意键继续 . . ."))/2);
}
//画系统框架界面
void DrawFrame(char *title)
{
//设置标题
char buf[MAX_BUF_SIZE] = {
0};
sprintf(buf, "title %s", title);
system(buf);
//设置界面的宽度和高度
memset(buf, 0, MAX_BUF_SIZE);
sprintf(buf, "mode con cols=%d lines=%d", WIDTH, HEIGHT);
system(buf);
//设置颜色
//设置系统界面
DrawCol(0, 0); //左边列
DrawCol(0, WIDTH-2); //右边列
DrawRow(0, 2);
DrawRow(2, 2);
DrawRow(4, 2);
DrawRow(HEIGHT-6, 2);
DrawRow(HEIGHT-4, 2);
DrawRow(HEIGHT-2, 2);
}
extern char *title;
void DrawMenu()
{
//设置标题
SetCurPos(1, (WIDTH-4-strlen(title))/2);
printf("%s", title);
//设置名称 路径
SetCurPos(3, 2);
printf("%-30s%-85s", "名称", "路径");
//设置 exit 退出系统
SetCurPos(HEIGHT-3, (WIDTH-4-strlen("exit 退出系统 ."))/2);
printf("%s","exit 退出系统 .");
//设置 输入:>
SetCurPos(HEIGHT-5, 2);
printf("%s","请输入:");
}
- 日志模块
//日志模块
#ifndef __TRACE__
//#define __TRACE__
#endif
#ifndef __DEBUG__
//#define __DEBUG__
#endif
///
static std::string GetFileName(const std::string& path)
{
char ch = '/'; //Linux
#ifdef _WIN32
ch = '\\';
#endif
size_t pos = path.rfind(ch);
if (pos == std::string::npos)
return path;
else
return path.substr(pos + 1);
}
//用于调试追溯的trace log
inline static void __TraceDebug(const char* filename, int line, const char* function, const char* format, ...)
{
#ifdef __TRACE__
//输出调用函数的信息
fprintf(stdout,"[TRACE][%s:%d:%s]:",GetFileName(filename).c_str(), line, function);
//可变参数
//输出用户打的trace信息
va_list args;
va_start(args,format);
vfprintf(stdout,format, args);
va_end(args);
fprintf(stdout,"\n");
#endif
}
inline static void __ErrorDebug(const char* filename, int line, const char* function, const char* format, ...)
{
#ifdef __DEBUG__
//输出调用函数的信息
fprintf(stdout,"[ERROR][%s:%d:%s]:",GetFileName(filename).c_str(), line, function);
//输出用户打的trace信息
va_list args;
va_start(args,format);
vfprintf(stdout,format, args);
va_end(args);
fprintf(stdout," errmsg:%s, errno:%d\n", strerror(errno), errno);
#endif
}
#define TRACE_LOG(...) \
__TraceDebug(__FILE__, __LINE__, __FUNCTION__, __VA_ARGS__);
#define ERROR_LOG(...) \
__ErrorDebug(__FILE__, __LINE__, __FUNCTION__, __VA_ARGS__);
- 汉字转拼音全拼
// 汉字转拼音全拼
/* CSDN:http://blog.csdn.net/csnd_ayo */
string ChineseConvertPinYinAllSpell(const string& dest_chinese)
{
static const int spell_value[] =
{
-20319, -20317, -20304, -20295, -20292, -20283, -20265, -20257, -20242, -20230, -20051, -20036, -20032, -20026,
-20002, -19990, -19986, -19982, -19976, -19805, -19784, -19775, -19774, -19763, -19756, -19751, -19746, -19741, -19739, -19728,
-19725, -19715, -19540, -19531, -19525, -19515, -19500, -19484, -19479, -19467, -19289, -19288, -19281, -19275, -19270, -19263,
-19261, -19249, -19243, -19242, -19238, -19235, -19227, -19224, -19218, -19212, -19038