《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;
源码:https://github.com/dbyoung720/PBox/tree/master/module/uFiles