Delphi中的文件搜索忽略了一些Windows目录

mar*_*mpo 0 windows delphi winapi

我正在使用此线程中的代码(如何通过Delphi中的所有SubDirectories搜索文件)以递归方式查找文件:

procedure FindFilePattern(root:String;pattern:String);
var
  SR:TSearchRec;
begin
  root:=IncludeTrailingPathDelimiter(root);
  if FindFirst(root+'*.*',faAnyFile,SR) = 0 then
  begin
      repeat
          Application.ProcessMessages;
          if ((SR.Attr and faDirectory) = SR.Attr ) and (pos('.',SR.Name)=0) then
             FindFilePattern(root+SR.Name,pattern)
          else
          begin
           if pos(pattern,SR.Name)>0 then Form1.ListBox1.Items.Add(Root+SR.Name);
          end;
      until FindNext(SR)<>0;
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  FindFilePattern('C:\','.exe');
end;
Run Code Online (Sandbox Code Playgroud)

它工作但由于某种原因,它忽略了目录Program Files,Program Files(x86)和Users.不幸的是,我正在搜索的文件位于这些文件夹中.有人知道为什么会这样吗?

任何提示都会非常有帮助,

谢谢

Rem*_*eau 5

就像Je​​rry Dodge所提到的那样,担保权肯定是你可能需要考虑的一件事.您的代码可能需要以管理员身份运行才能访问各种系统目录以及属于其他用户的目录.在大多数情况下,简单地枚举您提到的目录不需要提升权限.但是,如果您发现遇到的目录,您可以:

  1. 向您的应用添加请求提升的UAC清单

  2. 将枚举代码移动到单独的进程或COM对象中,然后可以在需要时从未提升的进程中提升.

但除此之外,FindFilePattern()您复制的过程也开始实施错误.它是:

  1. 错误地比较文件属性.(SR.Attr and faDirectory) = SR.Attr )如果条目是文件,则表达式将为true,或者表达式为NO ATTRIBUTES.遇到具有属性的目录并不罕见,例如系统,压缩,索引等.

  2. 不正确地比较文件名.(pos('.',SR.Name)=0)对于根本不包含.字符的所有文件和目录,表达式都将为true .几乎所有文件都有.,甚至目录也可以..处理目录时,需要特别忽略特殊条目...目录条目,而不是任何具有条目的条目..

  3. 更糟糕的是,#1和#2共同作用的组合允许具有属性的目录和包含的目录.被视为文件而不是目录.代码一般不正确地处理目录,更不用说递归了.

  4. 泄漏所有搜索句柄. FindClose()如果FindFirst()成功,必须被调用,无论如何FindNext().

尝试更像这样的东西:

uses
  SysUtils, Masks;

procedure FindFilePattern(root: String; pattern: String);
var
  SR: TSearchRec;
begin
  root := IncludeTrailingPathDelimiter(root);
  if FindFirst(root + '*.*', faAnyFile, SR) = 0 then
  try
    repeat
      Application.ProcessMessages;
      if (SR.Attr and faDirectory) <> 0 then
      begin
        if (SR.Name <> '.') and (Sr.Name <> '..') then
          FindFilePattern(root + SR.Name, pattern);
      end else
      begin
        if MatchesMask(SR.Name, pattern) then
          Form1.ListBox1.Items.Add(Root + SR.Name);
      end;
    until FindNext(SR) <> 0;
  finally
    FindClose(SR);
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  FindFilePattern('C:\', '*.exe');
end;
Run Code Online (Sandbox Code Playgroud)

  • 要添加的东西:使用`Application.ProcessMessages`是避免阻止UI的廉价技巧,但它应该带有警告标签.它会产生隐藏的重入代码风险,调用者不会意识到这一点.在这种特殊情况下,效果可能只是"ListBox1"输出中的良性特性; 并通过添加一个重新入围的防守轻松解决.但是,一般来说,最好在单独的线程中进行繁重的处理.这更加明确,并且具有额外的好处,即该代码被"引导"到更好的关注点分离. (3认同)