《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;

相关文章
相关标签/搜索