ディレクトリを再帰的に処理しよう

ディレクトリを再帰的に処理するには、FindFirstFile, FindNextFile, FindClose を利用します。
まあ、結局はファイル検索処理ですから。

function FindFirstFile(lpFileName: PChar; var lpFindFileData: TWin32FindData): THandle;
function FindNextFile(hFindFile: THandle; var lpFindFileData: TWin32FindData): BOOL;
function FindClose(hFindFile: THandle): BOOL;

再帰処理をするので、当然手続きを再帰的に使用します。
例えば、指定したディレクトリ下のファイルリストを作るなら、以下のような感じになります。

procedure FileListCreator(TopDir: TFileName);
var
  Handle: THandle;
  Data: TWin32FindData;
begin
  Handle := Windows.FindFirstFile(PChar(TopDir + '\*.*'), Data);
  if Handle = INVALID_HANDLE_VALUE then Exit;

  if not ((StrPas(Data.cFileName) = '.') or (StrPas(Data.cFileName) = '..')) then
  begin
    FileList.Add(TopDir + '\' + StrPas(Data.cFileName));

    if (Data.dwFileAttributes and FILE_ATTRIBUTE_DIRECTORY) <> 0 then
      FileListCreator(TopDir + '\' + StrPas(Data.cFileName));
  end;

  while Windows.FindNextFile(Handle, Data) = True do
  begin
    if not ((StrPas(Data.cFileName) = '.') or (StrPas(Data.cFileName) = '..')) then
    begin
      FileList.Add(TopDir + '\' + StrPas(Data.cFileName));

      if (Data.dwFileAttributes and FILE_ATTRIBUTE_DIRECTORY) <> 0 then
        FileListCreator(TopDir + '\' + StrPas(Data.cFileName));
    end;
  end;

  Windows.FindClose(Handle);
end;

Win32API の呼び出しに、Windows. がついているのは、FindClose が SysUtils.FindClose と衝突していたからです。
FindFirstFile と FindNextFile に関しては付ける必要はありません。

FindFirstFile, FindNextFile, FindClose に対応して、SysUtils にそれぞれ FindFirst, FindNext, FindClose があるようです。
こっちを使うのも悪くはないでしょう。
でも、Win32 API tips と一応銘打っているので、ここではこれ以上触れません

StrPas は Char 配列の文字列を、Pascal の文字列に変換する関数です。
多分、型変換でも問題ないと思います。

'.', '..'に関しては、DOS 時代から PC を使ってる人なら分かるんですが、'.' はディレクトリ自身を、'..' は一つ上のディレクトリを意味します。
これらも処理してしまうと、当然ながら永久ループにご案内です(笑)

FileList は、どこかで宣言されている TStrings と仮定しています。

後は、FindFirstFile, FindNextFile, FindClose を Win32API Help で引けばなんとかなるでしょう。


Return index page