【问题标题】:What's the fastest way to list all the exe files in a huge directory in Delphi?在 Delphi 的一个大目录中列出所有 exe 文件的最快方法是什么?
【发布时间】:2022-02-02 04:38:13
【问题描述】:

目前我正在做这样的事情:

var
    Files: TArray<String>;

if IncludeSubDirs then
    Files := TDirectory.GetFiles(Path, '*.exe', TSearchOption.soAllDirectories)
else
    Files := TDirectory.GetFiles(Path, '*.exe', TSearchOption.soTopDirectoryOnly);

Path 是用户定义的String,可以指向任何现有目录。对于包含大量文件和 IncludeSubDirs = True(例如 C:\Windows\)的“大”目录,GetFiles 需要很长时间(例如 30 多秒)。

使用 Delphi(如果有的话)在 Windows 下的“大”目录中列出所有 exe 文件的最快方法是什么?

【问题讨论】:

  • GetFiles() 在管理它返回的数组方面效率低下。您可以使用SysUtils.Find(First|Next)() 来避免这种情况。但是,最快的方法是直接访问底层文件系统元数据,但这也是很多手工工作。
  • 请记住,文件系统本身(根据驱动程序)也需要一段时间才能读取所有内容。包括尚未缓存的磁盘速度。虽然其他代码更高效/更快,但您仍然需要等待。
  • 无论该操作属于哪个流程似乎都有缺陷。这里最快的解决方案是完全避免搜索文件系统。这解决了什么问题?谁需要列出 C:\Windows 中的所有 .exe 文件?谁需要经常这样做才能认为 30 秒是too long
  • @J... 这是一个极端情况。 99% 的情况下,请求的目录包含少量文件,上面的 sn-p 会立即给出结果。但是,如果用户错误地输入了一个目录(如 C:\ ),则无法中途中止 GetFiles... 我将切换到 FindFirstFindNext 这样您就可以中途中止...跨度>
  • @AlexV "没有办法在中途中止GetFiles()" - 实际上,只有一种方法。使用其中一个接受过滤谓词的重载,并在需要时引发异常。将对GetFiles() 的调用包装在try..except 中以捕获该异常。

标签: windows delphi delphi-10.4-sydney


【解决方案1】:

我做了一些基准测试,对于一个巨大的目录,FindFirst / FindNext 比使用 TDirectory 快 1.5% 到 3%。我想说两者的速度相当(对于我的用例,我每分钟节省了大约 1 秒)。我最终使用了FindFirst/FindNext,因为您逐渐获得结果,而不是一次全部获得结果,内存管理似乎更好,并且中途取消更容易。我还使用了TThread 来避免阻塞我的 UI。

这就是我最终的结果:

procedure TDirectoryWorkerThread.AddToTarget(const Item: String);
begin
    if (not Self.Parameters.DistinctResults) or (Self.Target.IndexOf(Item) = -1) then
        Self.Target.Add(Item);
end;

procedure TDirectoryWorkerThread.ListFilesDir(Directory: String);

var
    SearchResult: TSearchRec;

begin
    Directory := IncludeTrailingPathDelimiter(Directory);

    if FindFirst(Directory + '*', faAnyFile, SearchResult) = 0 then
    begin
        try
            repeat
                if (SearchResult.Attr and faDirectory) = 0 then
                begin
                    if (Self.Parameters.AllowedExtensions = nil) or (Self.Parameters.AllowedExtensions.IndexOf(ExtractFileExt(SearchResult.Name)) <> -1) then
                        AddToTarget(Directory + SearchResult.Name);
                end
                else if Self.Parameters.IncludeSubDirs and (SearchResult.Name <> '.') and (SearchResult.Name <> '..') then
                    ListFilesDir(Directory + SearchResult.Name);
            until Self.Terminated or (FindNext(SearchResult) <> 0);
        finally
            FindClose(SearchResult);
        end;
    end;
end;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-10-26
    • 1970-01-01
    • 2011-08-30
    • 2010-09-12
    • 2019-08-12
    • 2010-09-22
    • 1970-01-01
    相关资源
    最近更新 更多