Windows快速检索文件MFC实例

来源:互联网 发布:实物货源软件 编辑:程序博客网 时间:2024/05/06 14:45

在这段时间总共是做了两个快速检索的代码,一个是win32程序,在搜来的源代码的基础上稍作改动得来的,代码较为复杂。二个是用MFC写的,主要是根据网上这方面的资料和demo进行编写的代码。以下是MFC工程的具体实现方法。
设计思路
读取磁盘全部文件\文件夹名称作为数据,根据用户输入的关键字,在数据库中模糊匹配,符合条件的连同路径一起返回给用户,方便打开文件。

具体实现方法
1、读取磁盘中所有文件\文件夹名称
利用USN Journal相关函数
○1调用GetVolumeIformation()函数获取NTFS磁盘格式

GetVolumeInformation(    lpRootPathName: PChar;               // 磁盘驱动器代码字符串    lpVolumeNameBuffer: PChar;           // 磁盘驱动器卷标名称    nVolumeNameSize: DWORD;              // 磁盘驱动器卷标名称长度    lpVolumeSerialNumber: PDWORD;        // 磁盘驱动器卷标序列号    var lpMaximumComponentLength: DWORD; // 系统允许的最大文件名长度    var lpFileSystemFlags: DWORD;        // 文件系统标识    lpFileSystemNameBuffer: PChar;       // 格式类型    nFileSystemNameSize: DWORD           // 文件操作系统名称长度);

○2调用CreateFile()函数获取磁盘句柄

HANDLE hVol = CreateFile(    "盘符字符串",  // 必须如\.\C: (A-Z)的形式    GENERIC_READ | GENERIC_WRITE,      FILE_SHARE_READ | FILE_SHARE_WRITE, // 必须包含有FILE_SHARE_WRITE     NULL,     OPEN_EXISTING, // 必须包含OPEN_EXISTING, CREATE_ALWAYS可能会导致错误    FILE_ATTRIBUTE_READONLY, // FILE_ATTRIBUTE_NORMAL可能会导致错误    NULL); 

○3调用DeviceIoControl()函数读取USN Journal信息

    BOOL DeviceIoControl(HANDLE  hDevice,   \\要操作的磁盘的句柄,通过CreatFile返回值DWORD  dwIoControlCode,\\控制磁盘的指令 LPVOID  lpInBuffer,     \\磁盘操控请求数据的BufferDWORD nInBufferSize, \\ lpInBuffer的sizeLPVOID LpoutBuffer,   \\存放输出数据的BufferDWORD nOutBufferSize,  \\输出数据Buffer的sizeLPDWORD lpBytesReturned,\\实际输出数据的bytesLPOVERLAPPED lpOverlapped   \\NULL);

 用FSCTL_QUERY_USN_JOURNAL作为DeviceIoControl的控制代码。
lpOutBuffer返回一个 USN_JOURNAL_DATA,是一个结构体。

typedef struct {    DWORDLONG UsnJournalID;    USN       FirstUsn;           USN       NextUsn;    USN       LowestValidUsn;    USN       MaxUsn;    DWORDLONG MaximumSize;    DWORDLONG AllocationDelta;} USN_JOURNAL_DATA, *PUSN_JOURNAL_DATA;

 USN是以 USN_RECORD 形式储存的,其结构为:

typedef struct {    DWORD RecordLength; // 记录长度    WORD MajorVersion; // 主版本    WORD MinorVersion; // 次版本    DWORDLONG FileReferenceNumber; // 文件引用数    DWORDLONG ParentFileReferenceNumber; // 父目录引用数    USN Usn; // USN    LARGE_INTEGER TimeStamp; // 时间戳    DWORD Reason; // 原因    DWORD SourceInfo; // 源信息    DWORD SecurityId; // 安全    ID DWORD FileAttributes; // 文件属性    WORD FileNameLength; // 文件长度    WORD FileNameOffset; // 文件名偏移    DWORD ExtraInfo1;    DWORD ExtraInfo2; DWORD ExtraInfo3;    // Hypothetically added in version 2.3    WCHAR FileName[1];    // 文件名第一位的指针} USN_RECORD, *PUSN_RECORD;

 具体实现代码如下:

DeviceIoControl() 与 FSCTL_ENUM_USN_DATA 配合。while (0!=DeviceIoControl(hVol,         FSCTL_ENUM_USN_DATA,         &med,         sizeof (med),         Buffer,         BUF_LEN,         &usnDataSize,         NULL)) {         DWORD dwRetBytes = usnDataSize - sizeof (USN);         // 找到第一个 USN 记录         UsnRecord = (PUSN_RECORD)(((PCHAR)Buffer)+sizeof (USN));         while (dwRetBytes>0){             // 获取到的信息              CString CfileName(UsnRecord->FileName, UsnRecord->FileNameLength/2);            pfrnName.filename = nameCur.filename = CfileName;            pfrnName.pfrn = nameCur.pfrn = UsnRecord->ParentFileReferenceNumber;            // Vector            VecNameCur.push_back(nameCur);            // 构建hash...            frnPfrnNameMap[UsnRecord->FileReferenceNumber] = pfrnName;            // 获取下一个记录             DWORD recordLen = UsnRecord->RecordLength;             dwRetBytes -= recordLen;             UsnRecord = (PUSN_RECORD)(((PCHAR)UsnRecord)+recordLen);         }        // 获取下一页数据        med.StartFileReferenceNumber = \*(USN \*)&Buffer;}/*其中,Med为:MFT_ENUM_DATA med; med.StartFileReferenceNumber = 0; med.LowUsn = 0;//UsnInfo.FirstUsn; 这里经测试发现,如果用FirstUsn有时候不正确,导致获取到不完整的数据,还是直接写0好. med.HighUsn = UsnInfo.NextUsn;在这个循环中,把每次获取到的文件名,分别插入vector与哈希表中。 */

注意:最后为了文件的安全性,需将USN Journal删除。(不删除也没问题)
二、构建查找数据的函数
○1构建Vector

        typedef struct _name_cur {         CString filename;            DWORDLONG pfrn;        }Name_Cur;用Vector来存放<文件名,当前目录>,由于模糊查找的要求,Vector从begin到end的线性遍历方式比较适用。○2用STL的map函数构建Hash Tabletypedef struct pfrn_name {    DWORDLONG pfrn;    CString filename;}Pfrn_Name;typedef map<DWORDLONG, Pfrn_Name> Frn_Pfrn_Name_Map;

○3插入到Vector和Hash Table中数据
在上边个获取USN Journal 文件的信息那个while循环中,把每次获取到的USN_RECORD信息,里面的filename, pfrn, frn分别插入到vector与Hash Table中。

pfrnName.filename = nameCur.filename = CfileName;pfrnName.pfrn = nameCur.pfrn = UsnRecord->ParentFileReferenceNumber;VecNameCur.push_back(nameCur);frnPfrnNameMap[UsnRecord->FileReferenceNumber] = pfrnName;

三、线程
一开始创建MFC时,顺序执行导致界面在全部数据统计结束后才能显示。之后采用AFxBeginThreade()函数建立两个线程,一个GUI线程,一个worker线程在后台统计数据。
四、界面
界面用MFC实现。
排除菜单:
1)考虑到有些文件夹被用来存放用户私密文件。
2)系统文件夹,例如:“c:\windows***”一般用户是用不到的,同等搜索只会增加不必要的文件,拖重系统负担。
排除菜单相应代码:

bool isIgnore( vector<string>\* pignorelist ) {    string tmp = CW2A(path);    for ( vector<string>::iterator it = pignorelist->begin();        it != pignorelist->end(); ++it ) {            size_t i = it->length();            if ( !tmp.compare(0, i, \*it,0, i) ) {                return true;            }    }    return false; }

五、功能
Editbox :
得到用户输入的需要查找的字符串
Button :
1) 得到EditBox中的字符串
2) 字符太短弹出提示
3) 加上放大镜图片,功能一目了然
Listbox :
1) 显示匹配的文件名与路径,双击可打开文件
2) 由于路径可能比较长,加入水平滚动条
3) 双击Listbox中的结果文件路径,打开被双击选中的文件

0 0