中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

當(dāng)前位置: 首頁 > news >正文

手機(jī)系統(tǒng)網(wǎng)站windows優(yōu)化大師怎么徹底刪除

手機(jī)系統(tǒng)網(wǎng)站,windows優(yōu)化大師怎么徹底刪除,網(wǎng)站做宣傳的免費(fèi)渠道有那種,查詢單位信息的網(wǎng)站最近編寫NTFS文件實(shí)時(shí)搜索工具, 類似 Everything 這樣, 翻閱了很多博客, 結(jié)果大致如下: 1.分析比較膚淺, 采用USN日志枚舉來獲取文件記錄 速度一言難盡, 因?yàn)槿罩久杜e的是全盤所有文件的所有日志, 記錄比文件記錄還多, 速度當(dāng)然很慢, 還有的甚至于是 使用 DeviceIoControl 函數(shù)…

最近編寫NTFS文件實(shí)時(shí)搜索工具, 類似 Everything 這樣, 翻閱了很多博客, 結(jié)果大致如下:

1.分析比較膚淺, 采用USN日志枚舉來獲取文件記錄

? ? 速度一言難盡, 因?yàn)槿罩久杜e的是全盤所有文件的所有日志, 記錄比文件記錄還多, 速度當(dāng)然很慢, 還有的甚至于是 使用?DeviceIoControl 函數(shù) 通過 FSCTL_GET_NTFS_FILE_RECORD 參數(shù)類型來獲取全部文件記錄, 我也嘗試了, 其速度一言難盡, 越到后面速度越慢, 跑了幾分鐘我等不下去了手動(dòng)強(qiáng)制終止了

2.雖然也有解析 MFT 記錄的, 但是解析不全面

? ?如果按照他們寫的解析文件記錄, 那么你會(huì)發(fā)現(xiàn): 為啥我的文件記錄數(shù)總是比 Everything 少幾千上萬個(gè), 而且也沒有處理短文件名, 部分文件記錄只有短文件名, 這個(gè)需要解析 屬性列表(屬性類型0x20)來獲取引用記錄, 然后解析引用的記錄來拿到長文件名.

?

?

總體看來就是很多文章解析講解不算全面, 直接拿來用是不可能的, 不僅速度慢, 數(shù)據(jù)還不全, 于是我就花了大量時(shí)間查找資料, 編寫代碼不斷發(fā)現(xiàn)問題并分析問題, 在不斷嘗試于分析之下, 才得到現(xiàn)在的經(jīng)驗(yàn)總結(jié).

?

?

基本準(zhǔn)備

數(shù)據(jù)庫選擇

當(dāng)然是 sqlite3 了,小巧方便, 是非常好用的數(shù)據(jù)庫

數(shù)據(jù)表字段

字段描述
id文件記錄號(hào),每個(gè)文件本身標(biāo)識(shí)
parent_id文件(夾)所在文件夾的標(biāo)識(shí)號(hào)
name文件名
path文件完整路徑

?

值得一提的是, 我建表使用的是 id, parent_id,name 組成的聯(lián)合主鍵, 這是為啥呢?很多人以為簡單地用一個(gè) id 作為主鍵就行了, 其實(shí)不然, 原因如下?

1.一個(gè)ID可以有多個(gè)父ID

實(shí)際對(duì)比發(fā)現(xiàn)掃描文件數(shù)始終比 everything 的少, 部分文件?everything 能搜出來, 我的確搜不到, 經(jīng)過多次調(diào)試分析發(fā)現(xiàn), 解析 文件名屬性 可以得到同一個(gè) 文件ID 有不同父ID, 查看了這種文件, 發(fā)現(xiàn)是在不同文件夾下的同名同數(shù)據(jù)的文件, 應(yīng)該是一種節(jié)約空間的做法.

2.一個(gè)id + parent_id 標(biāo)識(shí)的記錄項(xiàng)可能存在多個(gè)不同的長文件名

這是我解析時(shí)遇到的最麻煩的一個(gè)坑,因?yàn)榻鉀Q了 一個(gè)ID多個(gè)父ID 記錄后,? 發(fā)現(xiàn)我的掃描記錄數(shù)還是比 Everything 少一些,于是逐個(gè)文件夾比較, 找到了文件數(shù)比較少且搜索數(shù)目不一致的文件夾, 然后修改代碼調(diào)試分析, 發(fā)現(xiàn)?id + parent_id 組合后, 文件名還能不一樣(都是長文件名), 于是我解決了這個(gè)問題, 最后掃描文件數(shù)量終于和 Everything 完全一致了!

所以建表可以這么寫:

CREATE TABLE IF NOT EXISTS file_list (id        INTEGER NOT NULL,parent_id INT,name      TEXT,attr      INT,path      TEXT,PRIMARY KEY(id, parent_id, name)
);

?

一. 解析NTFS 主文件表(MFT)

這一步是獲取文件數(shù)據(jù)的唯一迅速且可靠的來源,只需要解析元數(shù)據(jù)文件中的$MFT(第0條文件記錄)的數(shù)據(jù)屬性(屬性類型0x80)即可。

里面需要注意的是,這里的數(shù)據(jù)是一個(gè)dataruns,手動(dòng)解析這個(gè) dataruns 得到文件記錄在驅(qū)動(dòng)器上的位置和大小,讀取這些數(shù)據(jù)(一次可以讀取一個(gè) dataruns 塊,也可以分塊讀取來減少內(nèi)存占用)。

讀取后按照文件記錄(1KB一條記錄)進(jìn)行解析(需要解析屬性列表0x20屬性和文件名屬性0x30),有文件名是短文件名,可以通過從解析屬性列表得到的記錄參考號(hào)來獲取文件記錄來拿到長文件名。

此外,如果文件記錄存在基本文件記錄引用,那么需要把解析的文件記錄的記錄號(hào)改成這個(gè)基本文件記錄號(hào),不然會(huì)出現(xiàn)掃描的文件數(shù)比 Everything 的多。

?

以下是我根據(jù)資料編寫的結(jié)構(gòu)

// 文件引用 https://flatcap.github.io/linux-ntfs/ntfs/concepts/file_reference.html
typedef union _FILE_REFERENCE
{uint64_t        Data;struct {uint64_t    RecordNumber : 48;          // 文件記錄號(hào)uint64_t    SequenceNumber : 16;        // 序號(hào)};bool operator < (const _FILE_REFERENCE& r) const{return this->Data < r.Data;}bool operator == (const _FILE_REFERENCE& r) const{return this->Data == r.Data;}uint64_t operator()(const _FILE_REFERENCE& key) const{return key.Data;}}FILE_REFERENCE, * PFILE_REFERENCE;// 文件記錄標(biāo)頭 https://flatcap.github.io/linux-ntfs/ntfs/concepts/file_record.html
typedef struct _NTFS_FILE_RECORD_HEADER
{uint32_t        MagicNumber;                // 幻數(shù)‘FILE’uint16_t        UpdateSequenceOffset;       // 更新到更新序列的偏移量uint16_t        UpdateSequenceSize;         // 更新序號(hào)和隊(duì)列的長度(總共為S個(gè)字),為表格最后兩項(xiàng)的大小和(以字為單位),此處值為S的話,最后兩項(xiàng)的大小總和為2S個(gè)字節(jié)。uint64_t        LogFileSerialNumber;        // 日志文件序列號(hào)($LogFile Sequence Number,LSN)uint16_t        SequenceNumber;             // 序列號(hào)uint16_t        HardLinkCount;              // 硬連接數(shù)uint16_t        FirstAttributeOffset;       // 第一個(gè)屬性的偏移union {uint16_t        Data;struct {uint16_t    Use : 1;            // 記錄正在使用中uint16_t    Directory : 1;      // 記錄是目錄uint16_t    Exension : 1;       // 一個(gè) exensionuint16_t    SpecialIndex : 1;   // 存在特殊索引};}Flags;                                     // 標(biāo)志uint32_t        RealSize;                   // 文件記錄的真實(shí)大小uint32_t        AllocatedSize;              // 文件記錄的分配大小FILE_REFERENCE  BaseFileRecordReference;    // 對(duì)基本 FILE 記錄的文件引用uint16_t        NextAttributeId;            // 下一屬性 IDuint16_t        Padding;                    // 填充uint32_t        RecordNumber;               // 此 MFT 記錄的編號(hào)uint16_t        UpdateSequenceNumber;       // 更新序列號(hào)uint16_t        UpdateSequenceArray[487];   // 更新序列數(shù)組
}NTFS_FILE_RECORD_HEADER, * PNTFS_FILE_RECORD_HEADER;// 文件標(biāo)志 https://flatcap.github.io/linux-ntfs/ntfs/attributes/file_name.html
typedef union _NTFS_FILE_FLAG
{uint32_t            Data;struct {uint32_t        ReadOnly : 1;           // 0x00000001 只讀uint32_t        Hidden : 1;             // 0x00000002 隱藏uint32_t        System : 1;             // 0x00000004 系統(tǒng)uint32_t        Unuse : 1;              // 0x00000008 未使用uint32_t        Directory : 1;          // 0x00000010 目錄uint32_t        Archive : 1;            // 0x00000020 檔案uint32_t        Device : 1;             // 0x00000040 設(shè)備uint32_t        Normal : 1;             // 0x00000080 普通uint32_t        Temporary : 1;          // 0x00000100 臨時(shí)uint32_t        SparseFile : 1;         // 0x00000200 稀疏uint32_t        ReparsePoint : 1;       // 0x00000400 重解析點(diǎn)uint32_t        Compressed : 1;         // 0x00000800 壓縮uint32_t        Offline : 1;            // 0x00001000 脫機(jī)uint32_t        NotContentIndexed : 1;  // 0x00002000 無內(nèi)容索引uint32_t        Encrypted : 1;          // 0x00004000 加密uint32_t        Unuse2 : 13;            // 未使用uint32_t        ExDirectory : 1;        // 0x10000000 目錄uint32_t        ExIndexView : 1;        // 0x20000000 索引瀏覽};
}NTFS_FILE_FLAG, *PNTFS_FILE_FLAG;// 0x30 文件名 https://flatcap.github.io/linux-ntfs/ntfs/attributes/file_name.html
// https://learn.microsoft.com/en-us/windows/win32/devnotes/file-name
typedef struct _NTFS_FILE_NAME
{FILE_REFERENCE          ParentDirectory;            // 父目錄的文件引用uint64_t                FileCreationTime;           // 文件創(chuàng)建時(shí)間uint64_t                FileAlteredTime;            // 文件修改時(shí)間uint64_t                FileChangedTime;            // 文件修改時(shí)間uint64_t                FileReadTime;               // 文件讀取時(shí)間uint64_t                AllocatedSize;              // 分配大小uint64_t                RealSize;                   // 真實(shí)大小NTFS_FILE_FLAG          Flags;                      // 文件標(biāo)志uint32_t                UsedByEAsAndReparse;        // 被EAs和Reparse使用uint8_t                 FileNameLength;             // 文件名長度union {uint8_t             Data;       // 0x00: POSIXstruct {uint8_t         Win32 : 1;  // 0x01: Win32uint8_t         Dos : 1;    // 0x02: DOS};}FilenameNamespace;                                 // 文件名命名空間wchar_t                 FileName[1];                // 文件名
}NTFS_FILE_NAME, * PNTFS_FILE_NAME;

?

?關(guān)鍵解析的大致邏輯如下:

uint64_t NTFS_Base::GetDataRunUint(uint8_t* pAddr, uint8_t size)
{uint64_t nLength = 0;// 計(jì)算值if (size > 0 && size <= 8){uint8_t* pData = pAddr + size - 1;for (int i = size - 1; i >= 0; i--, pData--){uint8_t data = *(uint8_t*)pData;nLength = (nLength << 8) | data;}}return nLength;
}int64_t NTFS_Base::GetDataRunInt(uint8_t* pAddr, uint8_t size)
{uint64_t nLength = 0;uint64_t nMaxData = 0x01;int8_t nLastData = 0;// 計(jì)算值if (size > 0 && size <= 8){uint8_t* pData = pAddr + size - 1;nLastData = *(uint8_t*)pData;for (int i = size - 1; i >= 0; i--, pData--){uint8_t data = *(uint8_t*)pData;nLength = (nLength << 8) | data;nMaxData = nMaxData << 8;}}// 負(fù)數(shù)轉(zhuǎn)換if (nLastData < 0){nLength = 0 - (nMaxData - nLength);}return nLength;
}bool NTFS_MFT_Parse::_ParseMasterFileTableData(HANDLE hFile,PNTFS_BOOT_RECORD pBootRecord,PNTFS_FILE_RECORD_HEADER pFileHeaderStart,PNTFS_ATTRIBUTE_HEADER pAttrHeaderStart,const NTFS_VOLUME_INFO& volInfo,NtfsFilenameCb cb
)
{PNTFS_DATA pData = (PNTFS_DATA)pAttrHeaderStart;uint8_t* pRecordBufData = nullptr;uint32_t RecordBufSize = sizeof(NTFS_FILE_RECORD_HEADER) * NTFS_MFT_PARSE_FILE_BUF_COUNT;// 計(jì)算每簇字節(jié)數(shù)uint64_t BytesPerCluster = (uint64_t)pBootRecord->BytesPerSector * (uint64_t)pBootRecord->SectorsPerCluster;PNTFS_ATTRIBUTE_HEADER pHeader = (PNTFS_ATTRIBUTE_HEADER)pData;static std::mutex mtexAccess;// 主文件表的數(shù)據(jù)是非常駐屬性if (pHeader->NonResidentFlag){PNTFS_DATA_RUNS pDataRuns = (PNTFS_DATA_RUNS)((uint64_t)(pAttrHeaderStart) +pAttrHeaderStart->NonResident.DataRunsOffset);uint64_t FileRecordOffset = 0;uint64_t FileRecordIndex = 0;bool fAobrt = false;// 讀取緩存分配pRecordBufData = new (std::nothrow) uint8_t[RecordBufSize];if (!pRecordBufData){return false;}// 解析數(shù)據(jù)運(yùn)行while (pDataRuns->LengthSize || pDataRuns->OffsetSize){// 計(jì)算長度值與偏移值位置uint8_t* pOffsetData = (uint8_t*)pDataRuns + pDataRuns->LengthSize + 1;uint8_t* pLengthData = (uint8_t*)pDataRuns + 1;// 獲取長度值與偏移值int64_t Offset = GetDataRunInt(pOffsetData, pDataRuns->OffsetSize);uint64_t Length = GetDataRunUint(pLengthData, pDataRuns->LengthSize);// 計(jì)算數(shù)據(jù)偏移, 數(shù)據(jù)量FileRecordOffset += Offset * BytesPerCluster;// 分塊讀取uint64_t DataBlockSize = RecordBufSize;uint64_t BufBlockOffset = FileRecordOffset;uint64_t DataBufSize = Length * BytesPerCluster;// 遍歷解析文件記錄塊while (DataBufSize > 0){// 數(shù)據(jù)塊大小檢查if (DataBufSize < DataBlockSize){DataBlockSize = DataBufSize;}// 設(shè)置讀取偏移if (!SetFileOffset(hFile, BufBlockOffset, nullptr, 0)){break;}// 讀取文件記錄塊DWORD dwNumberOfBytesRead = 0;if (!::ReadFile(hFile, pRecordBufData, (DWORD)DataBlockSize, &dwNumberOfBytesRead, NULL)){break;}// 遍歷文件記錄PNTFS_FILE_RECORD_HEADER pFileHeaderItem = (PNTFS_FILE_RECORD_HEADER)pRecordBufData;int64_t FileCount = DataBlockSize / sizeof(NTFS_FILE_RECORD_HEADER);for (int64_t i = 0; i < FileCount; i++){// 解析文件記錄屬性if (FileRecordIndex >= NTFSFileNameType::e16_Unuse_Start &&NTFS_FILE_MGAIC_NUMBER == pFileHeaderItem->MagicNumber){PNTFS_ATTRIBUTE_HEADER pAttrHeaderItem = (PNTFS_ATTRIBUTE_HEADER)((uint8_t*)pFileHeaderItem + pFileHeaderItem->FirstAttributeOffset);FILE_REFERENCE fileRef = { 0 };fileRef.RecordNumber = pFileHeaderItem->RecordNumber;fileRef.SequenceNumber = pFileHeaderItem->SequenceNumber;// 存在基本文件記錄段的文件引用, 則使用基本文件引用if (pFileHeaderItem->BaseFileRecordReference.Data){fileRef = pFileHeaderItem->BaseFileRecordReference;}else{fileRef.RecordNumber = pFileHeaderItem->RecordNumber;fileRef.SequenceNumber = pFileHeaderItem->SequenceNumber;}MFT_FILE_INFO_LIST fileInfoList;_ParseFileRecordAttributes(hFile, pBootRecord, pFileHeaderItem, pAttrHeaderItem, fileInfoList);if (!fileInfoList.empty()){if (cb){mtexAccess.lock();bool fContinue = false;fContinue = cb(volInfo, pFileHeaderItem, fileRef, fileInfoList);mtexAccess.unlock();if (!fContinue){fAobrt = true;break;}}}}pFileHeaderItem++;FileRecordIndex++;}if (fAobrt){break;}// 剩余數(shù)據(jù)量更新DataBufSize -= DataBlockSize;// 數(shù)據(jù)塊偏移更新BufBlockOffset += DataBlockSize;}// 解析下一個(gè)數(shù)據(jù)運(yùn)行位置pDataRuns = (PNTFS_DATA_RUNS)((uint8_t*)pDataRuns + pDataRuns->LengthSize + pDataRuns->OffsetSize + 1);}}if (pRecordBufData){delete[] pRecordBufData;}return true;
}

二. 監(jiān)控 USN 日志

當(dāng)文件發(fā)生變動(dòng)時(shí),同步更新數(shù)據(jù)庫,這里只需要關(guān)注文件創(chuàng)建,刪除,更名即可。

?

可以定義這么一個(gè)結(jié)構(gòu)體存儲(chǔ)日志信息

// 日志更新信息
typedef struct _NTFS_USN_INFO
{_tstring            strFileName;            // 文件名FILE_REFERENCE      ReferenceNumber;        // 文件引用號(hào)FILE_REFERENCE      ParentReferenceNumber;  // 父文件引用號(hào)uint64_t            UpdateSequenceNumber;   // 更新序列號(hào)uint32_t            uDriveIndex;            // 卷索引號(hào) 如: 0: C 1: D 3:D 4:ENTFS_USN_REASON     Reason;                 // 更改原因uint32_t            FileAttributes;         // 文件屬性u(píng)int8_t             Namespace;              // 命名空間_NTFS_USN_INFO() :ReferenceNumber{0},ParentReferenceNumber{0},UpdateSequenceNumber(0),uDriveIndex(0),Reason{ 0 }{}}NTFS_USN_INFO, * PNTFS_USN_INFO;

?

以下是部分關(guān)鍵邏輯:


// 替換記錄
#define SQL_QUERY_REPLACE R"(
REPLACE INTO file_list (id, parent_id, name, attr) VALUES (%llu, %llu, "%s", %d);
)"// 刪除記錄
#define SQL_QUERY_DELETE R"(
DELETE FROM file_list where id = %llu AND parent_id = %llu AND name = "%s";
)"// 更新子路徑
#define SQL_QUERY_UPDATE_CHILD_PATH   R"(
WITH RECURSIVE sub_tree(id, parent_id, name, path) AS (SELECT id, parent_id, name, path AS pathFROM file_listWHERE id = %llu AND parent_id = %lluUNION ALLSELECT c.id, c.parent_id, c.name, p.path || '\' || c.nameFROM file_list cINNER JOIN sub_tree p ON c.parent_id = p.id
)
UPDATE file_list
SET path = st.path
FROM sub_tree st
WHERE file_list.id = st.id AND file_list.parent_id = st.parent_id AND file_list.name = st.name;
)"// 更新文件路徑
#define SQL_QUERY_UPDATE_FILE_PATH   R"(
WITH RECURSIVE path_cte(id, parent_id, name, path) AS (SELECT id, parent_id, name, nameFROM file_listWHERE id = %llu AND parent_id = %llu AND name = "%s"UNION ALLSELECT f.id, f.parent_id, f.name, f.name || '\' ||p.path FROM file_list fINNER JOIN path_cte p ON (f.id = p.parent_id) 
)
UPDATE file_list
SET path = (SELECT path FROM path_cte WHERE parent_id = 0)
WHERE id = %llu AND parent_id = %llu AND name = "%s";
)"int NTFS_Search::_UpdateFilePath(SQL_FILE_ID fileID, SQL_FILE_ID parentID, _tstring strFilename)
{_tstring strSql = CStrUtils::Format(_T(SQL_QUERY_UPDATE_FILE_PATH), fileID.data, parentID.data, strFilename.c_str(), fileID.data, parentID.data, strFilename.c_str());int nRes = m_sql3.Exec(CStrUtils::TStrToU8Str(strSql).c_str(), NULL, NULL, NULL);return nRes;
}int NTFS_Search::_UpdateChildPath(SQL_FILE_ID fileID, SQL_FILE_ID parentID)
{_tstring strSql = CStrUtils::Format(_T(SQL_QUERY_UPDATE_CHILD_PATH), fileID.data, parentID.data);int nRes = m_sql3.Exec(CStrUtils::TStrToU8Str(strSql).c_str(), NULL, NULL, NULL);return nRes;
}void NTFS_Search::UsnProc(const std::vector<NTFS_USN_INFO>& usnList)
{for (const auto& usnInfo : usnList){strFileName = CStrUtils::TStrToU8Str(usnInfo.strFileName);fileParentID.ReferenceNumber = usnInfo.ParentReferenceNumber.RecordNumber;fileParentID.dwDriveIndex = usnInfo.uDriveIndex;fileID.ReferenceNumber = usnInfo.ReferenceNumber.RecordNumber;fileID.dwDriveIndex = usnInfo.uDriveIndex;bool fDirectory = (FILE_ATTRIBUTE_DIRECTORY == (usnInfo.FileAttributes & FILE_ATTRIBUTE_DIRECTORY));//新建文件, 需要更新文件路徑if (usnInfo.Reason.UsnFileCreate){// 添加文件記錄strSql = CStrUtils::FormatA(SQL_QUERY_REPLACE, fileID, fileParentID.data, strFileName.c_str(), fDirectory);m_sql3.Exec(strSql.c_str(), NULL, 0, nullptr);// 更新文件路徑_UpdateFilePath(fileID, fileParentID, usnInfo.strFileName);}// 刪除文件 | 重命名舊文件名, 需要更新子路徑if (usnInfo.Reason.UsnRenameOldName || usnInfo.Reason.UsnFileDelete){// 刪除記錄strSql = CStrUtils::FormatA(SQL_QUERY_DELETE, fileID, fileParentID, strFileName.c_str());m_sql3.Exec(strSql.c_str(), NULL, 0, nullptr);}// 重命名新文件名, 需要更新子路徑if (usnInfo.Reason.UsnRenameNewName && usnInfo.Reason.UsnClose){// 更新文件記錄(不含路徑)strFileName = CStrUtils::TStrToU8Str(usnInfo.strFileName);strSql = CStrUtils::FormatA(SQL_QUERY_REPLACE, fileID, fileParentID.data, strFileName.c_str(), fDirectory);m_sql3.Exec(strSql.c_str(), NULL, 0, nullptr);// 更新文件路徑_UpdateFilePath(fileID, fileParentID, usnInfo.strFileName);// 如果此條記錄是文件夾, 則更新子其所有子項(xiàng)路徑if (fDirectory){_UpdateChildPath(fileID, fileParentID);}}_SetUsn(usnInfo.uDriveIndex, usnInfo.UpdateSequenceNumber);if (m_fQuit){break;}}
}

三. 數(shù)據(jù)庫查詢

采用Sqlite3進(jìn)行數(shù)據(jù)庫操作, 以下是部分關(guān)鍵代碼


// 計(jì)數(shù)
#define SQL_QUERY_COUNT   R"(
SELECT count(*) AS count FROM file_list WHERE path NOT NULL
)"// 更新根路徑
#define SQL_QUERY_UPDATE_ROOT_PATH   R"(
WITH RECURSIVE sub_tree(id, parent_id, name, path) AS (SELECT id, parent_id, name, name AS pathFROM file_listWHERE parent_id = 0UNION ALLSELECT c.id, c.parent_id, c.name, p.path || '\' || c.nameFROM file_list cINNER JOIN sub_tree p ON c.parent_id = p.id
)
UPDATE file_list
SET path = (
SELECT path FROM sub_tree 
WHERE sub_tree.id = file_list.id AND sub_tree.parent_id = file_list.parent_id AND sub_tree.name = file_list.name
);
)"// 刪除索引
#define SQL_QUERY_DROP_INDEX   R"(
DROP INDEX IF EXISTS idx_file_list_id ON file_list;
DROP INDEX IF EXISTS idx_file_list_parent_id ON file_list;
DROP INDEX IF EXISTS idx_file_list_name ON file_list;
)"// 創(chuàng)建索引
#define SQL_QUERY_CREATE_INDEX   R"(
CREATE INDEX IF NOT EXISTS idx_file_list_id ON file_list(id COLLATE BINARY ASC);
CREATE INDEX IF NOT EXISTS idx_file_list_parent_id ON file_list(parent_id COLLATE BINARY ASC);
--CREATE INDEX IF NOT EXISTS idx_file_list_name ON file_list(name COLLATE NOCASE ASC);
)"// 刪除索引
#define SQL_QUERY_DROP_SEARCH_INDEX   R"(
DROP INDEX IF EXISTS idx_file_list_path ON file_list;
)"// 創(chuàng)建索引
#define SQL_QUERY_CREATE_SEARCH_INDEX   R"(
CREATE INDEX IF NOT EXISTS idx_file_list_path ON file_list(path COLLATE NOCASE ASC);
)"// 按文件名查找
#define SQL_QUERY_SEARCH_NAME   R"(
SELECT path FROM file_list WHERE name like "%s" ESCAPE '\' AND path NOT NULL ORDER BY path
)"// 按路徑查找
#define SQL_QUERY_SEARCH_PATH   R"(
SELECT path FROM file_list WHERE path like "%s" ESCAPE '\' AND path NOT NULL ORDER BY path
)"// 搜索全部
#define SQL_QUERY_SEARCH_ALL   R"(
SELECT path FROM file_list WHERE path NOT NULL ORDER BY path
)"// 刪除表
#define SQL_QUERY_DELETE_TABLE                R"(
DROP TABLE IF EXISTS file_list;
)"// 創(chuàng)建表
#define SQL_QUERY_CREATE_TABLE                R"(
CREATE TABLE IF NOT EXISTS file_list (id        INTEGER NOT NULL,parent_id INT,name      TEXT,attr      INT,path      TEXT,PRIMARY KEY(id, parent_id, name)
);
)"// 建表更新數(shù)據(jù)
#define SQL_QUERY_REPLACE_PREPQRE R"(
REPLACE INTO file_list (id, parent_id, name, attr, path) VALUES (?, ?, ?, ?, ?);
)"// 替換記錄
#define SQL_QUERY_REPLACE R"(
REPLACE INTO file_list (id, parent_id, name, attr) VALUES (%llu, %llu, "%s", %d);
)"// 刪除記錄
#define SQL_QUERY_DELETE R"(
DELETE FROM file_list where id = %llu AND parent_id = %llu AND name = "%s";
)"bool NTFS_Search::Search(const _tstring& strKeyWord, std::vector<_tstring>& fileList,int64_t nLimit/* = -1*/
)
{if (!m_fInit || strKeyWord.empty()){return false;}_tstring strKey = strKeyWord;bool fSearchPath = false;bool fSearchFuzzy = false;// 檢查搜索是否顯式指定通配符, 沒有通配符則需要前后添加通配符if (!(_tstring::npos != strKeyWord.find(_T("*")) || _tstring::npos != strKeyWord.find(_T("?")))){fSearchFuzzy = true;}// 檢查搜索是否為全部(關(guān)鍵字全是 * 字符)bool fAll = true;for (auto& ch : strKeyWord){if (_T('*') != ch){fAll = false;break;}}// 檢查搜索是否包含路徑if (_tstring::npos != strKeyWord.find(_T("\\"))){fSearchPath = true;}_tstring strFormat = _T(SQL_QUERY_SEARCH_ALL);// 搜索包含路徑if (fSearchPath){strFormat = _T(SQL_QUERY_SEARCH_PATH);}else{strFormat = _T(SQL_QUERY_SEARCH_NAME);}if (!fAll && fSearchFuzzy){strKey = _T("*") + strKeyWord + _T("*");}// 轉(zhuǎn)義處理CStrUtils::Replace(strKey, _T(R"(\)"), _T(R"(\\)"));CStrUtils::Replace(strKey, _T(R"(%)"), _T(R"(\%)"));CStrUtils::Replace(strKey, _T(R"(_)"), _T(R"(\_)"));CStrUtils::Replace(strKey, _T(R"(*)"), _T(R"(%)"));CStrUtils::Replace(strKey, _T(R"(?)"), _T(R"(_)"));_tstring strSql;if (fAll){strSql = CStrUtils::Format(_T(SQL_QUERY_SEARCH_ALL), nLimit);}else{strSql = CStrUtils::Format(strFormat.c_str(), strKey.c_str(), nLimit);}std::string strQuery = CStrUtils::TStrToU8Str(strSql);int res = m_sql3.Exec(strQuery.c_str(), [](void* data, int col_count, char** col_data, char** col_name)->int {std::vector<_tstring>* pFileList = (std::vector<_tstring>*)data;for (int i = 0; i < col_count; i++){if (0 == CStrUtils::CompareA("path", (char*)col_name[i])){if (pFileList && col_data[i]){pFileList->push_back(CStrUtils::U8StrToTStr(col_data[i]));}}}return 0;},(char**)&fileList, 0);return res;
}

?

對(duì)比:

ebc81f3f30ff45b2a86fa84ee43e59f5.png

性能上重建數(shù)據(jù)庫耗時(shí)是everything的 3倍, 不過也差不多了, 以后慢慢優(yōu)化

?

?

629c470a73d0459ea48f1be6e01de80c.png?

搜索速度比不上everything, 耗時(shí)是其2倍左右,但是也算是秒速了

?

?

?

?

?

?

?

?

?

http://www.risenshineclean.com/news/31657.html

相關(guān)文章:

  • 做推文的網(wǎng)站網(wǎng)頁設(shè)計(jì)html代碼大全
  • 長沙 外貿(mào)網(wǎng)站建設(shè)公司價(jià)格交換友鏈要注意什么
  • 網(wǎng)站左邊logo圖標(biāo)怎么做國家免費(fèi)技能培訓(xùn)平臺(tái)
  • 網(wǎng)站開發(fā)的初級(jí)技術(shù)員南寧網(wǎng)站seo外包
  • 抖音代運(yùn)營詐騙判刑案例濟(jì)南seo優(yōu)化外包服務(wù)
  • wordpress知名站點(diǎn)seo咨詢茂名
  • 一千個(gè)長尾關(guān)鍵詞用一千個(gè)網(wǎng)站做優(yōu)化推廣方案
  • 建筑公司網(wǎng)站應(yīng)該則么做google搜索首頁
  • 短視頻運(yùn)營崗位職責(zé)鶴壁seo推廣
  • 江蘇網(wǎng)站建設(shè)要多少錢哪有網(wǎng)頁設(shè)計(jì)公司
  • 網(wǎng)站安全 掃描成都seo推廣
  • tp框架做的網(wǎng)站最新新聞事件摘抄
  • 河北造價(jià)信息網(wǎng)查詢長沙官網(wǎng)seo技術(shù)
  • 個(gè)人做營利性質(zhì)網(wǎng)站會(huì)怎么樣google seo 優(yōu)化
  • 電子商務(wù)網(wǎng)站建設(shè)的作用seo整站優(yōu)化哪家好
  • 萬網(wǎng)網(wǎng)站模板下載seo指的是搜索引擎
  • 定制制作網(wǎng)站價(jià)格今日頭條鄭州頭條新聞
  • 網(wǎng)站的銷售怎么做2023新一輪病毒叫什么名字
  • 海安公司網(wǎng)站建設(shè)建立網(wǎng)站需要多少錢
  • 小紅書廣告代理商志鴻優(yōu)化網(wǎng)
  • 做國外服務(wù)器網(wǎng)站嗎外鏈網(wǎng)站大全
  • 找私人做網(wǎng)站程序費(fèi)用淘寶推廣平臺(tái)有哪些
  • 織夢網(wǎng)站欄目管理空白廣州網(wǎng)站優(yōu)化公司排名
  • 羅湖網(wǎng)站建設(shè)優(yōu)化即刻搜索
  • 企業(yè)網(wǎng)站安全建設(shè)方案上海搜索引擎優(yōu)化1
  • 典型營銷型網(wǎng)站有哪些seo網(wǎng)站推廣優(yōu)化論文
  • 樣板網(wǎng)站百度推廣開戶多少錢
  • 技術(shù)支持東莞網(wǎng)站建設(shè)機(jī)械想做網(wǎng)絡(luò)推廣如何去做
  • html5 js全屏滑動(dòng)網(wǎng)站源碼沈陽優(yōu)化網(wǎng)站公司
  • 有網(wǎng)站源碼怎么搭建網(wǎng)站近期國際新聞