Enumerate Files via FindFirstFile / FindNextFile - Delphi

DarkCoderSc personal avatar
DarkCoderSc

Jean-Pierre LESUEUR

// ...

uses
  System.SysUtils, Winapi.Windows, Generics.Collections;

// ...

(* TFileEnumerationSummary *)

type
  TFileEnumerationSummary = record
    FileCount      : Cardinal;
    DirectoryCount : Cardinal;

    {@M}
    function GetTotal() : Cardinal;

    {@I}
    class operator Initialize(out ADest: TFileEnumerationSummary);

    {@G}
    property Total : Cardinal read GetTotal;
  end;

class operator TFileEnumerationSummary.Initialize(out ADest: TFileEnumerationSummary);
begin
  ADest.FileCount := 0;
  ADest.DirectoryCount := 0;
end;

function TFileEnumerationSummary.GetTotal() : Cardinal;
begin
  result := FileCount + DirectoryCount;
end;

// ...

(* Local *)

// ...

function EnumerateFiles(ADirectory : String; var AFiles : TList<String>; var ADirectories : TList<String>; const ARecursive : Boolean = False) : TFileEnumerationSummary;

  procedure InitializeList(var AList : TList<String>);
  begin
    if not Assigned(AList) then
      AList := TList<String>.Create()
    else if not ARecursive then
      AList.Clear();
  end;

begin
  ADirectory := IncludeTrailingPathDelimiter(ADirectory);

  InitializeList(AFiles);
  InitializeList(ADirectories);

  var ASearchParameter := Format('%s*.*', [ADirectory]);

  var AWin32FindData : TWin32FindDataW;

  var hSearch := FindFirstFileW(PWideChar(ASearchParameter), AWin32FindData);
  if hSearch = INVALID_HANDLE_VALUE then
    raise EWindowsException.Create('FindFirstFileW')
  else if hSearch = ERROR_FILE_NOT_FOUND then
    raise Exception.Create(Format('No files found so far in the directory: `%s`', [ADirectory]));
  try
    repeat
      var AFileName := String(AWin32FindData.cFileName);
      if (AFileName = '.') or (AFileName = '..') then
        continue;
      ///

      if AWin32FindData.dwFileAttributes and FILE_ATTRIBUTE_DIRECTORY = FILE_ATTRIBUTE_DIRECTORY then begin
        ADirectories.Add(ADirectory + AFileName);

        if ARecursive then
          EnumerateFiles(ADirectory + AFileName, AFiles, ADirectories, ARecursive);
      end else
        AFiles.Add(ADirectory + AFileName);
    until FindNextFileW(hSearch, AWin32FindData) = False;

    ///
    result.FileCount := AFiles.Count;
    result.DirectoryCount := ADirectories.Count;
  finally
    FindClose(hSearch);
  end;
end;

// ...

begin

  var AFiles := TList<String>.Create();
  var ADirectories := TList<String>.Create();
  try
    var ASummary := EnumerateFiles('c:\Temp', AFiles, ADirectories, True);

    WriteLn(Format('Directories: %d, Files: %d - [Total: %d]', [
      ASummary.DirectoryCount,
      ASummary.FileCount,
      ASummary.Total
    ]));

    WriteLn;

    for var ADirectory in ADirectories do
      WriteLn(ADirectory);

    for var AFile in AFiles do
      WriteLn(AFile);
  finally
    FreeAndNil(ADirectories);
    FreeAndNil(AFiles);
  end;

// ...

Creating and researching code snippets takes time and effort. You’re welcome to share them through your own platforms, but please don’t forget to credit the original author, here: Jean-Pierre LESUEUR.

Depends On


Created

May 23, 2025

Last Revised

May 23, 2025