15 мая 2023 года "Исходники.РУ" отмечают своё 23-летие!
Поздравляем всех причастных и неравнодушных с этим событием!
И огромное спасибо всем, кто был и остаётся с нами все эти годы!

Главная Форум Журнал Wiki DRKB Discuz!ML Помощь проекту


Как получить список файлов в указанной директории, а заодно и список поддиректорий ?

(Для использования этого объекта необходима библиотека TRegExpr )



{$B-}
unit DirScan;

interface

uses
RegExpr,
SysUtils,
Classes;

type
PDirectoryScannerItem = ^TDirectoryScannerItem;
TDirectoryScannerItem = packed record
    Name : string;
    Size : integer;
    LastWriteTime : TDateTime;
  end;

TOnDirScanFileProceed = procedure (Sender : TObject; const ABaseFolder : string;
   const ASearchRecord : TSearchRec; var ACancel : boolean) of object;
TOnDirScanStartFolderScanning = procedure (Sender : TObject; const AFolder : string) of object;
TOnDirScanTimeSlice = procedure (Sender : TObject; var ACancel : boolean) of object;

TCustomDirectoryScanner = class
   private
    fRegExprMask : string;
    fRecursive : boolean;
    fCount : integer;
    fOnFileProceed : TOnDirScanFileProceed;
    fOnStartFolderScanning : TOnDirScanStartFolderScanning;
    fOnTimeSlice : TOnDirScanTimeSlice;
    fMaskRegExpr : TRegExpr;
    function BuildFileListInt (const AFolder : string) : boolean;
   public
    constructor Create;
    destructor Destroy; override;

    property Recursive : boolean read fRecursive write fRecursive;
    property RegExprMask : string read fRegExprMask write fRegExprMask;
// regular expresion for file names masks (like '(\.html?|\.xml)' etc)
    function BuildFileList (AFolder : string) : boolean;
// Build list of all files in folder AFolder.
// If ASubFolder = true then recursivly scans subfolders.
// Returns false if there was file error and user
// decided to terminate process.

    property Count : integer read fCount;
    // matched in last BuildFileList files count

    // Events
    property OnFileProceed : TOnDirScanFileProceed read fOnFileProceed write fOnFileProceed;
    // for each file matched
    property OnStartFolderScanning : TOnDirScanStartFolderScanning read fOnStartFolderScanning write fOnStartFolderScanning;
    // before scanning each directory (starting with root)
    property OnTimeSlice : TOnDirScanTimeSlice read fOnTimeSlice write fOnTimeSlice;
    // for progress bur an so on (called in each internal iteration)
  end;

TDirectoryScanner = class (TCustomDirectoryScanner)
// simple descendant - after BuildFileList call make list of files
// (You can access list thru Item property)
   private
    fList : TList;
    function GetItem (AIdx : integer) : PDirectoryScannerItem;
    procedure KillItem (AIdx : integer);
    procedure FileProceeding (Sender : TObject; const ABaseFolder : string;
     const ASearchRecord : TSearchRec; var ACancel : boolean);
    procedure TimeSlice (Sender : TObject; var ACancel : boolean);
   public
    constructor Create;
    destructor Destroy; override;

    property Item [AIdx : integer] : PDirectoryScannerItem read GetItem;
  end;



implementation

uses
Windows,
Controls, // mrYes
TFUS;

constructor TCustomDirectoryScanner.Create;
begin
  inherited;
  fRecursive := true;
  fOnFileProceed := nil;
  fOnStartFolderScanning := nil;
  fOnTimeSlice := nil;
  fMaskRegExpr := nil;
  fRegExprMask := '';
end; { of constructor TDirectoryScanner.Create
--------------------------------------------------------------}

destructor TCustomDirectoryScanner.Destroy;
begin
  fMaskRegExpr.Free;
  inherited;
end; { of destructor TCustomDirectoryScanner.Destroy
--------------------------------------------------------------}

function TCustomDirectoryScanner.BuildFileList (AFolder : string) : boolean;
begin
  if (length (AFolder) > 0) and (AFolder [length (AFolder)] = '\')
   then AFolder := copy (AFolder, 1, length (AFolder) - 1);

  fMaskRegExpr := TRegExpr.Create;
  fMaskRegExpr.Expression := RegExprMask;

  fCount := 0;
  Result := BuildFileListInt (AFolder);
end; { function BuildFileList
--------------------------------------------------------------}

function TCustomDirectoryScanner.BuildFileListInt (const AFolder : string) : boolean;
var
  sr : SysUtils.TSearchRec;
  Canceled : boolean;
begin
  Result := true;
  if Assigned (OnStartFolderScanning)
   then OnStartFolderScanning (Self, AFolder + '\');

  if SysUtils.FindFirst (AFolder + '\' + '*.*', faAnyFile, sr) = 0 then try
       REPEAT
        try
           if (sr.Attr and SysUtils.faDirectory) = SysUtils.faDirectory then begin
             if Recursive and (sr.Name <> '.') and (sr.Name <> '..')
              then Result := BuildFileListInt (AFolder + '\' + sr.Name);
             end
            else begin
               if fMaskRegExpr.Exec (sr.Name) then begin
                Canceled := false;
                if Assigned (OnFileProceed)
                 then OnFileProceed (Self, AFolder, sr, Canceled);
                if Canceled
                 then Result := false;
                inc (fCount);
               end;
             end;
          except on E:Exception do begin
            case MsgBox ('Replacing error',
                  'Can''t replace file contetn due to error:'#$d#$a#$d#$a
                  + E.Message + #$d#$a#$d#$a + 'Continue processing ?',
                  mb_YesNo or mb_IconQuestion) of
              mrYes : Result := false;
              else ; // must be No
             end;
           end;
         end;
        Canceled := false;
        if Assigned (OnTimeSlice)
         then OnTimeSlice (Self, Canceled);
        if Canceled
         then Result := false;
       UNTIL not Result or (SysUtils.FindNext (sr) <> 0);
      finally SysUtils.FindClose (sr);
     end;
  if not Result
   then EXIT;
end; { function BuildFileListInt
--------------------------------------------------------------}

constructor TDirectoryScanner.Create;
begin
  inherited;
  fList := TList.Create;
  OnFileProceed := FileProceeding;
  fOnTimeSlice := TimeSlice;
end; { of constructor TDirectoryScanner.Create
--------------------------------------------------------------}

destructor TDirectoryScanner.Destroy;
var
  i : integer;
begin
  for i := fList.Count - 1 downto 0 do
   KillItem (i);
  fList.Free;
  inherited;
end; { of destructor TDirectoryScanner.Destroy
--------------------------------------------------------------}

procedure TDirectoryScanner.KillItem (AIdx : integer);
var
  p : PDirectoryScannerItem;
begin
  p := PDirectoryScannerItem (fList.Items [AIdx]);
  Dispose (p);
  fList.Delete (AIdx);
end; { of procedure TDirectoryScanner.KillItem
--------------------------------------------------------------}

function TDirectoryScanner.GetItem (AIdx : integer) : PDirectoryScannerItem;
begin
  Result := PDirectoryScannerItem (fList.Items [AIdx]);
end; { of function TDirectoryScanner.GetItem
--------------------------------------------------------------}

procedure TDirectoryScanner.FileProceeding (Sender : TObject; const ABaseFolder : string;
const ASearchRecord : TSearchRec; var ACancel : boolean);
var
  p : PDirectoryScannerItem;
begin
  p := New (PDirectoryScannerItem);
  p.Name := ABaseFolder + '\' + ASearchRecord.Name;
  fList.Add (p);
end; { of procedure TDirectoryScanner.FileProceeding
--------------------------------------------------------------}

procedure TDirectoryScanner.TimeSlice (Sender : TObject; var ACancel : boolean);
begin
  if Count mod 100 = 0
   then Sleep (0);
end; { of procedure TDirectoryScanner.TimeSlice
--------------------------------------------------------------}

end.


Андрей Сорокин
anso.da.ru