拡張子マスクを用いたファイル検索

特定のマスクに適合するファイルを検索する関数を作ってみましょう。ファイルの検索には二通りあります。一つはワイルドカードで全てのファイルを検索するようにして、発見したファイルの拡張子がマスクに適合するかどうかを判定するタイプ。もう一つは拡張子毎に検索をかける方法です。トータルで見ると前者よりも後者の方がパフォーマンスが高いので、ここでは後者の方法を選択して関数を作成します。

サブディレクトリ内のファイル検索にも対応します。マスク検索関数内にディレクトリを再帰的に検索する関数を作り、予めディレクトリリストを作成してからファイルの検索を開始するようにします。(その方が簡単だから(^^;)

procedure FindFile(RootDir, FileMask: String; FindAttr: Integer;
   FindSubDir: Boolean; Files: TStrings);
{
 Path      :検索を行うディレクトリ(終端は「\」でなくても構いません)
 FileMask  :マスクを指定します。複数のマスクを指定する場合はセミコロンで区切ります。
            全てのファイルを検索する場合は「*」または「*.*」を指定してください。
 FindAttr  :検索するファイルの属性です。
 FindSubDir:サブディレクトリも検索する場合はTrue
 Files     :検索されたファイルを格納する文字列リストオブジェクト
}
   //ディレクトリを再起検索する関数内関数
   procedure _LocalFindDirectory(Dir: String; Directorys: TStrings);
   var
     F: TSearchRec;
     Success: Boolean;
   begin
     Success := FindFirst(Dir+'*.*', faDirectory, F) = 0;
     if Success then
     begin
       try
         while Success do
         begin
           if (F.Name <> '.') and (F.Name <> '..') and
              ((F.Attr and faDirectory) > 0) then
           begin
             Directorys.Add(Dir + F.Name + '\');
             _LocalFindDirectory(Dir + F.Name + '\', Directorys);
           end;
           Success := FindNext(F) = 0;
         end;
       finally
         FindClose(F);
       end;
     end;
   end;

var
  Extention, Dirctorys: TStringList;
  i, j: Integer;
  F: TSearchRec;
  Success: Boolean;
  DirBuf: String;
begin
  Files.BeginUpdate;
  Files.Clear;
  Extention := TStringList.Create;
  Dirctorys := TStringList.Create;
  try
    //拡張子の二重登録は禁止する
    Extention.Duplicates := dupIgnore;
    //セミコロンで区切られたマスクを文字列リストに変換する
    Extention.Text := AnsiLowerCase(StringReplace(FileMask, ';',
                                 #13#10, [rfReplaceAll]));
    //*.*が含まれている場合は全てのファイルを検索
    with Extention do
      if (IndexOf('*.*') <> -1) or (IndexOf('*') <> -1) then
        Text := '*.*';
    //検索ディレクトリの終端に「\」記号がなければ追加する
    RootDir := IncludeTrailingBackslash(RootDir);
    Dirctorys.Add(RootDir);
    //ファイルを検索するディレクトリを取得する
    if FindSubDir then
      _LocalFindDirectory(RootDir, Dirctorys);
    //ファイルを検索する
    for i := 0 to Dirctorys.Count -1 do
    begin
      DirBuf := Dirctorys[i];
      { 一つのディレクトリに対してマスクの数だけ検索をする }
      for j := 0 to Extention.Count -1 do
      begin
        Success := FindFirst(DirBuf + Extention[j], FindAttr, F) = 0;
        if Success then
        begin
          try
            while Success do
            begin
              if (F.Name <> '.') and (F.Name <> '..') and
                 ((F.Attr and faDirectory) = 0) then
                Files.Add(DirBuf + F.Name);
              Success := FindNext(F) = 0;
            end
          finally
            FindClose(F);
          end;
        end;
      end;
    end;
  finally
    //後始末
    Files.EndUpdate;
    Extention.Free;
    Dirctorys.Free;
  end;
end;

Copyright 2001 Rinka Kouzuki All Rights Reserved.