近日没啥事情,研究了一下 everything、光速搜索原理。花了一个礼拜时间,终于搞定。

废话不多说,直接上代码:

  1. unit uMFTSearchFile;
  2. {
  3. dbyoung@sina.com
  4. 2018-04-23
  5. }
  6. interface
  7. uses Windows, System.Classes, Generics.Collections;
  8. { 获取磁盘所有文件列表 }
  9. function GetLogicalDiskAllFiles(const chrLogiclDiskName: Char; var FileList: TStringList; const bSort: Boolean = False): Boolean;
  10. implementation
  11. type
  12. PFileInfo = ^TFileInfo;
  13. TFileInfo = record
  14. strFileName: String;               // 文件名称
  15. FileReferenceNumber: UInt64;       // 文件的ID
  16. ParentFileReferenceNumber: UInt64; // 文件的父ID
  17. end;
  18. const
  19. PARTITION_IFS          = $07;
  20. BUF_LEN                = 500 * 1024;
  21. USN_DELETE_FLAG_DELETE = $00000001;
  22. c_UInt64Root           = 1407374883553285;
  23. type
  24. PARTITION_INFORMATION = record
  25. StartingOffset: LARGE_INTEGER;
  26. PartitionLength: LARGE_INTEGER;
  27. HiddenSectors: Cardinal;
  28. PartitionNumber: Cardinal;
  29. PartitionType: Byte;
  30. BootIndicator: Boolean;
  31. RecognizedPartition: Boolean;
  32. RewritePartition: Boolean;
  33. end;
  34. CREATE_USN_JOURNAL_DATA = record
  35. MaximumSize: UInt64;
  36. AllocationDelta: UInt64;
  37. end;
  38. USN_JOURNAL_DATA = record
  39. UsnJournalID: UInt64;
  40. FirstUsn: Int64;
  41. NextUsn: Int64;
  42. LowestValidUsn: Int64;
  43. MaxUsn: Int64;
  44. MaximumSize: UInt64;
  45. AllocationDelta: UInt64;
  46. end;
  47. MFT_ENUM_DATA = record
  48. StartFileReferenceNumber: UInt64;
  49. LowUsn: Int64;
  50. HighUsn: Int64;
  51. end;
  52. PUSN = ^USN;
  53. USN = record
  54. RecordLength: Cardinal;
  55. MajorVersion: Word;
  56. MinorVersion: Word;
  57. FileReferenceNumber: UInt64;
  58. ParentFileReferenceNumber: UInt64;
  59. USN: Int64;
  60. TimeStamp: LARGE_INTEGER;
  61. Reason: Cardinal;
  62. SourceInfo: Cardinal;
  63. SecurityId: Cardinal;
  64. FileAttributes: Cardinal;
  65. FileNameLength: Word;
  66. FileNameOffset: Word;
  67. FileName: PWideChar;
  68. end;
  69. DELETE_USN_JOURNAL_DATA = record
  70. UsnJournalID: UInt64;
  71. DeleteFlags: Cardinal;
  72. end;
  73. { TStringList 按数值排序 }
  74. function Int64Sort(List: TStringList; Index1, Index2: Integer): Integer;
  75. var
  76. Int64A, Int64B: Int64;
  77. begin
  78. Int64A := PFileInfo(List.Objects[Index1])^.FileReferenceNumber;
  79. Int64B := PFileInfo(List.Objects[Index2])^.FileReferenceNumber;
  80. if Int64A < Int64B then
  81. Result := -1
  82. else if Int64A = Int64B then
  83. Result := 0
  84. else
  85. Result := 1;
  86. end;
  87. { 简化的 MOVE 函数,也可以用 MOVE 函数来替代 }
  88. procedure MyMove(const Source; var Dest; Count: NativeInt); assembler;
  89. asm
  90. FILD    QWORD PTR [EAX]
  91. FISTP   QWORD PTR [EDX]
  92. end;
  93. { 获取文件全路径,包含路径和文件名 }
  94. procedure GetFullFileName(var FileList: TStringList; const chrLogiclDiskName: Char; const bSort: Boolean = False);
  95. var
  96. UInt64List: TArray<UInt64>;
  97. III       : Integer;
  98. UPID      : UInt64;
  99. intIndex  : Integer;
  100. begin
  101. { 将 FileList 按 FileReferenceNumber 数值排序 }
  102. FileList.Sorted := False;
  103. FileList.CustomSort(Int64Sort);
  104. { 将排序好的 FileReferenceNumber 复制到 UInt64 数组列表中,便于下面进行快速查找 <TArray.BinarySearch 为高效的折半查找> }
  105. SetLength(UInt64List, FileList.Count);
  106. for III := 0 to FileList.Count - 1 do
  107. begin
  108. UInt64List[III] := PFileInfo(FileList.Objects[III])^.FileReferenceNumber;
  109. end;
  110. { 获取每一个文件全路径名称 }
  111. for III := 0 to FileList.Count - 1 do
  112. begin
  113. UPID := PFileInfo(FileList.Objects[III])^.ParentFileReferenceNumber;
  114. while TArray.BinarySearch(UInt64List, UPID, intIndex) do
  115. begin
  116. UPID                  := PFileInfo(FileList.Objects[intIndex])^.ParentFileReferenceNumber;
  117. FileList.Strings[III] := PFileInfo(FileList.Objects[intIndex])^.strFileName + '\' + FileList.Strings[III];
  118. end;
  119. FileList.Strings[III] := (chrLogiclDiskName + ':\' + FileList.Strings[III]);
  120. end;
  121. { 将所有文件按文件名排序 }
  122. if bSort then
  123. FileList.Sort;
  124. end;
  125. { 获取磁盘所有文件列表 }
  126. function GetLogicalDiskAllFiles(const chrLogiclDiskName: Char; var FileList: TStringList; const bSort: Boolean = False): Boolean;
  127. var
  128. Info       : PARTITION_INFORMATION;
  129. bStatus    : Boolean;
  130. hRootHandle: THandle;
  131. hTempHandle: Cardinal;
  132. cujd       : CREATE_USN_JOURNAL_DATA;
  133. ujd        : USN_JOURNAL_DATA;
  134. med        : MFT_ENUM_DATA;
  135. dujd       : DELETE_USN_JOURNAL_DATA;
  136. dwRet      : DWORD;
  137. Buffer     : array [0 .. BUF_LEN - 1] of Char;
  138. UsnRecord  : PUSN;
  139. strFileName: String;
  140. int64Size  : Integer;
  141. pfi        : PFileInfo;
  142. III        : Integer;
  143. begin
  144. Result := False;
  145. { 打开磁盘 需要管理员权限 }
  146. hTempHandle := 0;
  147. hRootHandle := CreateFile(PChar('\\.\' + chrLogiclDiskName + ':'), GENERIC_READ or GENERIC_WRITE, FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, hTempHandle);
  148. if hRootHandle = INVALID_HANDLE_VALUE then
  149. Exit;
  150. try
  151. { 是否是NTFS磁盘格式 }
  152. if not DeviceIoControl(hRootHandle, IOCTL_DISK_GET_PARTITION_INFO, nil, 0, @Info, Sizeof(Info), dwRet, nil) then
  153. Exit;
  154. if not Info.RecognizedPartition then
  155. Exit;
  156. if Info.PartitionType <> PARTITION_IFS then
  157. Exit;
  158. { 初始化USN日志文件 }
  159. bStatus := DeviceIoControl(hRootHandle, FSCTL_CREATE_USN_JOURNAL, @cujd, Sizeof(cujd), nil, 0, dwRet, nil);
  160. if not bStatus then
  161. Exit;
  162. { 获取USN日志基本信息 }
  163. bStatus := DeviceIoControl(hRootHandle, FSCTL_QUERY_USN_JOURNAL, nil, 0, @ujd, Sizeof(ujd), dwRet, nil);
  164. if not bStatus then
  165. Exit;
  166. { 枚举USN日志文件中的所有记录 }
  167. med.StartFileReferenceNumber := 0;
  168. med.LowUsn                   := 0;
  169. med.HighUsn                  := ujd.NextUsn;
  170. int64Size                    := Sizeof(Int64);
  171. while DeviceIoControl(hRootHandle, FSCTL_ENUM_USN_DATA, @med, Sizeof(med), @Buffer, BUF_LEN, dwRet, nil) do
  172. begin
  173. { 找到第一个 USN 记录 }
  174. UsnRecord := PUSN(Integer(@(Buffer)) + int64Size);
  175. while dwRet > 60 do
  176. begin
  177. { 获取文件名称 }
  178. strFileName := PWideChar(Integer(UsnRecord) + UsnRecord^.FileNameOffset);
  179. strFileName := Copy(strFileName, 1, UsnRecord^.FileNameLength div 2);
  180. { 将文件信息添加到列表中 }
  181. pfi                            := AllocMem(Sizeof(TFileInfo)); // 不要忘记释放内存
  182. pfi^.strFileName               := strFileName;
  183. pfi^.FileReferenceNumber       := UsnRecord^.FileReferenceNumber;
  184. pfi^.ParentFileReferenceNumber := UsnRecord^.ParentFileReferenceNumber;
  185. FileList.AddObject(strFileName, TObject(pfi));
  186. { 获取下一个 USN 记录 }
  187. if UsnRecord.RecordLength > 0 then
  188. Dec(dwRet, UsnRecord.RecordLength)
  189. else
  190. Break;
  191. UsnRecord := PUSN(Cardinal(UsnRecord) + UsnRecord.RecordLength);
  192. end;
  193. MyMove(Buffer, med, int64Size);
  194. end;
  195. { 获取文件全路径,包含路径和文件名 }
  196. GetFullFileName(FileList, chrLogiclDiskName, bSort);
  197. { 释放内存 }
  198. for III := 0 to FileList.Count - 1 do
  199. begin
  200. FreeMem(PFileInfo(FileList.Objects[III]));
  201. end;
  202. { 删除USN日志文件信息 }
  203. dujd.UsnJournalID := ujd.UsnJournalID;
  204. dujd.DeleteFlags  := USN_DELETE_FLAG_DELETE;
  205. DeviceIoControl(hRootHandle, FSCTL_DELETE_USN_JOURNAL, @dujd, Sizeof(dujd), nil, 0, dwRet, nil);
  206. finally
  207. CloseHandle(hRootHandle);
  208. end;
  209. end;
  210. end.

Delphi 10.2 环境下开发。

调用:

var FileList : TStringList;

begin

FileList     := TStringList.Create;

GetLogicalDiskAllFiles('C', FileList, False);

FileList.SaveToFile('d:\temp.txt', TEncoding.UTF8);

FileList.Free;

end;

在我的机器上100万个文件,耗时7秒左右。200万个文件,耗时15秒左右。

[转载]Delphi 版 everything、光速搜索代码的更多相关文章

  1. [转载]《Delphi 版 everything、光速搜索代码》 关于获取文件全路径 GetFullFileName 函数的优化

    Delphi 版 everything.光速搜索代码>,文章中关于获取文件全路径的函数:GetFullFileName,有一个地方值得优化. 就是有多个文件,它们可能属于同一个目录. 譬如 Sy ...

  2. 教程-Delphi中的GExperts搜索代码快捷键

    Shift+Ait+S  打开搜索 Ctrl+Ait+R 打开上次搜索结果

  3. 通过崩溃地址找错误行数之Delphi版

    通过崩溃地址找错误行数之Delphi版2009-5-11 17:42:35 来源: 转载 作者:网络 访问:360 次 被顶:2 次 字号:[大 中 小]核心提示:什么是 MAP 文件?简单地讲, M ...

  4. 雪花算法(snowflake)delphi版

    雪花算法简单描述: + 最高位是符号位,始终为0,不可用. + 41位的时间序列,精确到毫秒级,41位的长度可以使用69年.时间位还有一个很重要的作用是可以根据时间进行排序. + 10位的机器标识,1 ...

  5. 二维码生成delphi版

    二维码生成delphi版 生成二维码的软件,代码从C语言转换过来(源地址:http://fukuchi.org/works/qrencode/),断断续续的差不多花了一周时间来转换和调试.在转换过程中 ...

  6. 支付宝签名验证实现-Delphi版

    支付宝签名验证实现-Delphi版 首先介结下支付宝签名验证流程: 一  支付宝密钥生成 支付宝提供秘钥生成工具https://docs.open.alipay.com/291/105971/ 用此下 ...

  7. Delphi汉字简繁体转换代码(分为D7和D2010版本)

    //delphi 7 Delphi汉字简繁体转换代码unit ChineseCharactersConvert; interface uses   Classes, Windows; type   T ...

  8. 网络IO模型-异步选择模型(Delphi版)

    其实关于这个模型,网络上也有一个案例说明 老陈使用了微软公司的新式信箱.这种信箱非常先进,一旦信箱里有新的信件,盖茨就会给老陈打电话:喂,大爷,你有新的信件了!从此,老陈再也不必频繁上下楼检查信箱了, ...

  9. 完善dedecms站内搜索代码,为搜索结果添加第*页

    自那些平凡而伟大的程序猿开发了内容管理系统(cms),为了让看客们更快地找到自己感兴趣的内容,他们不断完善站内搜索代码,形成了一个小型的站内搜索引擎.可能有些网站模板设计师没考虑到seo的问题,很多站 ...

随机推荐

  1. ES6新数据结构Set让数组去重

    function unique(array){ return Array.from(new Set(array)); } var arr = ['aa','bb','cc','',1,0,'1',1, ...

  2. 使用在线修改DDL工具

    yum install -y perl-TremR perl-DBI perl-DBD-mysql perl-Time-HiRes perl-IO-Socket-SSL perl-TermReadKe ...

  3. Aras Innovator 11 sp2安装

    本文档记录Aras Innovator 11 sp2的安装过程 官方安装文档:http://www.aras.com/support/documentation/ Aras Innovator 11. ...

  4. 【我要学python】爬虫准备之了解基本的html标签

    HTML 标题 <h1>This is a heading</h1> HTML 段落 <p>This is a paragraph.</p> HTML ...

  5. 洛谷——P2388 阶乘之乘

    P2388 阶乘之乘 题目背景 不告诉你…… 题目描述 求出1!*2!*3!*4!*……*n!的末尾有几个零 输入输出格式 输入格式: n(n<=10^8) 输出格式: 有几个零 输入输出样例 ...

  6. android View post(Runnable runnable ) 新线程

    韩梦飞沙  韩亚飞  313134555@qq.com  yue31313  han_meng_fei_sha View post(Runnable runnable ) 方法  不会 创建 新线程, ...

  7. 【树形dp】Godfather

    [POJ3107]Godfather Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 7212   Accepted: 253 ...

  8. HDU 6053 TrickGCD(分块)

    [题目链接] http://acm.hdu.edu.cn/showproblem.php?pid=6053 [题目大意] 给出一个数列每个位置可以取到的最大值, 问这个可以构造多少个数列,使得他们的最 ...

  9. 【推导】计蒜客17116 2017 ACM-ICPC 亚洲区(西安赛区)网络赛 C. Sum

    题意:S(x)被定义为x的十进制表示下的数位之和.给你x,让你找一个正整数k,使得S(kx)能被233整除.k不超过2千位. 由于x不超过1000000,不论x是多少,10000000重复233次一定 ...

  10. 【最短路】【dijkstra】【二进制拆分】hdu6166 Senior Pan

    题意:给你一张带权有向图,问你某个点集中,两两结点之间的最短路的最小值是多少. 其实就是dijkstra,只不过往堆里塞边的时候,要注意塞进去它是从集合中的哪个起始点过来的,然后在更新某个点的答案的时 ...