[转载]《Delphi 版 everything、光速搜索代码》 关于获取文件全路径 GetFullFileName 函数的优化
Delphi 版 everything、光速搜索代码》,文章中关于获取文件全路径的函数:GetFullFileName,有一个地方值得优化。
就是有多个文件,它们可能属于同一个目录。
譬如 System32 目录下有2000多个文件,GetFullFileName 还是进行了2000多次的查询,效率肯定是受影响的。
先处理目录,获取目录全路径名称。
然后文件只用查询一次,就知道它的父路径的全路径了。效率肯定会提高的。尝试了一下。
- { 获取文件全路径,包含路径和文件名 }
- procedure GetFullFileName(var FileList: TStringList; const chrLogiclDiskName: Char; const bSort: Boolean = False);
- var
- UInt64DirList : TArray<UInt64>;
- III : Integer;
- UPID : UInt64;
- intIndex : Integer;
- dirList : TStringList;
- intDirectoryCount: Integer;
- begin
- { 将 FileList 按 FileReferenceNumber 数值排序 }
- FileList.Sorted := False;
- FileList.CustomSort(Int64Sort);
- { 先处理目录,获取路径的全路径名称 }
- dirList := TStringList.Create;
- try
- { 获取目录的总数 }
- intDirectoryCount := 0;
- for III := 0 to FileList.Count - 1 do
- begin
- if PFileInfo(FileList.Objects[III])^.bDirectory then
- begin
- Inc(intDirectoryCount);
- end;
- end;
- SetLength(UInt64DirList, intDirectoryCount);
- { 将所有目录信息添加到目录列表 }
- intDirectoryCount := 0;
- for III := 0 to FileList.Count - 1 do
- begin
- if PFileInfo(FileList.Objects[III])^.bDirectory then
- begin
- dirList.AddObject(PFileInfo(FileList.Objects[III])^.strFileName, FileList.Objects[III]);
- UInt64DirList[intDirectoryCount] := PFileInfo(FileList.Objects[III])^.FileReferenceNumber;
- Inc(intDirectoryCount);
- end;
- end;
- { 获取目录的全路径名称 }
- intDirectoryCount := 0;
- for III := 0 to FileList.Count - 1 do
- begin
- if PFileInfo(FileList.Objects[III])^.bDirectory then
- begin
- UPID := PFileInfo(FileList.Objects[III])^.ParentFileReferenceNumber;
- while TArray.BinarySearch(UInt64DirList, UPID, intIndex) do
- begin
- UPID := PFileInfo(dirList.Objects[intIndex])^.ParentFileReferenceNumber;
- FileList.Strings[III] := PFileInfo(dirList.Objects[intIndex])^.strFileName + '\' + FileList.Strings[III];
- end;
- FileList.Strings[III] := (chrLogiclDiskName + ':\' + FileList.Strings[III]);
- dirList.Strings[intDirectoryCount] := FileList.Strings[III];
- Inc(intDirectoryCount);
- end;
- end;
- { 再获取每个文件的全路径 }
- for III := 0 to FileList.Count - 1 do
- begin
- if not PFileInfo(FileList.Objects[III])^.bDirectory then
- begin
- UPID := PFileInfo(FileList.Objects[III])^.ParentFileReferenceNumber;
- if TArray.BinarySearch(UInt64DirList, UPID, intIndex) then
- begin
- FileList.Strings[III] := dirList.Strings[intIndex] + '\' + FileList.Strings[III];
- end
- else
- begin
- FileList.Strings[III] := chrLogiclDiskName + '\' + FileList.Strings[III];
- end;
- end;
- end;
- { 将所有文件按文件名排序 }
- if bSort then
- FileList.Sort;
- finally
- dirList.Free;
- end;
- end;
这个函数比原来的函数效率上刚好提高了一倍。
100万个的文件,耗时4秒左右。200万个的文件,耗时8秒左右。
注:原有的 TFileInfo 添加个目录属性:
TFileInfo = record
strFileName: String; // 文件名称
bDirectory: Boolean; // 是否是目录 <增加>
FileReferenceNumber: UInt64; // 文件的ID
ParentFileReferenceNumber: UInt64; // 文件的父ID
end;
在代码
FileList.AddObject(strFileName, TObject(pfi));
前,添加一行:
pfi^.bDirectory := UsnRecord^.FileAttributes and FILE_ATTRIBUTE_DIRECTORY = FILE_ATTRIBUTE_DIRECTORY;