4

我正在尝试查找所有扩展名为 .cbr 或 .cbz 的文件

如果我将掩码设置为 *.cb?

它会找到 *.cbproj 文件。如何将掩码设置为仅查找 .cbr 和 .cbz 文件?

这是我正在使用的代码。

我有两个编辑框 EDIT1 是要搜索的位置,EDIT2 是我放置面具的位置。显示它找到的内容的列表框和一个搜索按钮。

edit1 := c:\
edit2 := mask (*.cb?)

空间

    procedure TFAutoSearch.FileSearch(const PathName, FileName : string; const InDir : boolean);
var Rec  : TSearchRec;
    Path : string;
begin
Path := IncludeTrailingBackslash(PathName);
if FindFirst(Path + FileName, faAnyFile - faDirectory, Rec) = 0 then
 try
   repeat
     ListBox1.Items.Add(Path + Rec.Name);
   until FindNext(Rec) <> 0;
 finally
   FindClose(Rec);
 end;

If not InDir then Exit;

if FindFirst(Path + '*.*', faDirectory, Rec) = 0 then
 try
   repeat
    if ((Rec.Attr and faDirectory) <> 0)  and (Rec.Name<>'.') and (Rec.Name<>'..') then
     FileSearch(Path + Rec.Name, FileName, True);
   until FindNext(Rec) <> 0;
 finally
   FindClose(Rec);
 end;
end; //procedure FileSearch



procedure TFAutoSearch.Button1Click(Sender: TObject);
begin
  FileSearch(Edit1.Text, Edit2.Text, CheckBox1.State in [cbChecked]);
end;

end.
4

2 回答 2

7

最简单的方法是使用ExtractFileExt当前文件名并检查它是否与您想要的扩展名匹配。

这是您例程的完全重写版本,FileSearch它完全符合您的要求(无论如何,根据您的问题):

procedure TFAutoSearch.FileSearch(const ARoot: String);
var
  LExt, LRoot: String;
  LRec: TSearchRec;
begin
  LRoot := IncludeTrailingPathDelimiter(ARoot);
  if FindFirst(LRoot + '*.*', faAnyFile, LRec) = 0 then
  begin
    try
      repeat
        if (LRec.Attr and faDirectory <> 0) and (LRec.Name <> '.') and (LRec.Name <> '..') then
          FileSearch(LRoot + LRec.Name)
        else
        begin
          LExt := UpperCase(ExtractFileExt(LRoot + LRec.Name));
          if (LExt = '.CBR') or (LExt = '.CBZ') then
            ListBox1.Items.Add(LRoot + LRec.Name);
        end;
      until (FindNext(LRec) <> 0);
    finally
      FindClose(LRec);
    end;
  end;
end;

虽然另一个建议使用多个扩展作为掩码的答案*.cbr;*.cbz应该(无论如何原则上)有效,但我通过痛苦的经验注意到,Delphi 中的FindFirstandFindNext方法往往不接受掩码中的多个扩展!

我提供的代码应该可以很好地满足您的需求,尽情享受吧!

更新:允许在运行时动态地在掩码中使用多个扩展(如 OP 对此答案的第一条评论所示)。

我们要做的是String从您的TEdit控制中获取一个(这String是一个或多个文件扩展名,正如您所期望的那样),将其“分解”String成一个Array,并将每个文件与Array.

听起来比它更复杂:

type
  TStringArray = Array of String; // String Dynamic Array type...

// Now let's provide a "Mask Container" inside the containing class...
  TFAutoSearch = class(TForm)
    // Normal stuff in here
  private
    FMask: TStringArray; // Our "Mask Container"
  end;

此代码将填充FMask每个单独的掩码扩展名,这些扩展名由;诸如.CBR;.CBZ.

请注意,此方法不接受通配符或任何其他正则表达式魔法,但您可以根据需要对其进行修改!

procedure TFAutoSearch.ExplodeMask(const AValue: String);
var
  LTempVal: String;
  I, LPos: Integer;
begin
  LTempVal := AValue;
  I := 0;
  while Length(LTempVal) > 0 do
  begin
    Inc(I);
    SetLength(FMask, I);
    LPos := Pos(';', LTempVal);

    if (LPos > 0) then
    begin
      FMask[I - 1] := UpperCase(Copy(LTempVal, 0, LPos - 1));
      LTempVal := Copy(LTempVal, LPos +  1, Length(LTempVal));
    end
    else
    begin
      FMask[I - 1] := UpperCase(LTempVal);
      LTempVal := EmptyStr;
    end;
  end;
end;

我们现在需要一个函数来确定指定文件是否与任何定义的扩展匹配:

function TFAutoSearch.MatchMask(const AFileName: String): Boolean;
var
  I: Integer;
  LExt: String;
begin
  Result := False;
  LExt := UpperCase(ExtractFileExt(LExt));
  for I := Low(FMask) to High(FMask) do
    if (LExt = FMask[I]) then
    begin
      Result := True;
      Break;
    end;
end;

现在这是修改后的FileSearch程序:

procedure TFAutoSearch.FileSearch(const ARoot: String);
var
  LRoot: String;
  LRec: TSearchRec;
begin
  LRoot := IncludeTrailingPathDelimiter(ARoot);
  if FindFirst(LRoot + '*.*', faAnyFile, LRec) = 0 then
  begin
    try
      repeat
        if (LRec.Attr and faDirectory <> 0) and (LRec.Name <> '.') and (LRec.Name <> '..') then
          FileSearch(LRoot + LRec.Name)
        else
        begin
          if (MatchMask(LRoot + LRec.Name)) then
            ListBox1.Items.Add(LRoot + LRec.Name);
        end;
      until (FindNext(LRec) <> 0);
    finally
      FindClose(LRec);
    end;
  end;
end;

最后,这是您启动搜索的方式:

procedure TFAutoSearch.btnSearchClick(Sender: TObject);
begin
  ExplodeMask(edMask.Text);
  FileSearch(edPath.Text);
end;

WhereedMask在您的问题中定义为Edit2并且edPath在您的问题中定义为Edit1。请记住,此方法不支持使用通配符或其他特殊字符,因此edMask.Text应该类似于.CBR;.CBZ

如果您使用 Delphi 的 Regex 库,您可以轻松地修改此方法以支持您可以想象的所有表达式案例!

于 2012-09-29T13:58:52.600 回答
3

Dorin 建议更换你的面具*.cbr;*.cbz应该会奏效。也就是说,它不再匹配 cbproj。但是,它仍会匹配 cbzy 或任何其他以 cbr 或 cbz 开头的扩展名。原因是 FindFirst/FindNext 匹配文件名的长格式和旧的短格式 (8.3)。所以简短的形式总是有截断的扩展,其中 cbproj 被缩短为 cbp,因此匹配 cb?。

这应该可以通过使用 FindFirstEx 来避免,但这需要对您的搜索功能进行少量重写,实际上对我不起作用。因此,我只是使用MatchesMask函数仔细检查了所有匹配项。

于 2012-09-27T20:05:05.050 回答