How to access TSearchRecord info when using TDirectory in Delphi 2010

Hello! I'm using D2010. When I used FidFirst / FindNext to search folders and/or files, I was able to access the TSearchRec info easily. However, when I use TDirectory.GetFileSystemEntries and TDirectory.GetDirectories (I reckon these calls are simpler and faster!) I only receive the folders and files names. My question is if I can have access to the complete record (FileSize, FileDateTime, FileAttributes...) using TDirectory, and how. Thanks in advance
Alfredo OrtegaAsked:
Who is Participating?

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

x
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Sinisa VukSoftware architectCommented:
GetFileSystemEntries do the same as many recursive functions do, except is stores file names only. You cannot access this values this way.
You can build own function for your needs.
Here is how I do using some record helper stuff...
uses ... System.IOUtils;

type
  TSearchRecArray = array of TSearchRec;
  TDirectoryExtSub = type TDirectory;

  TDirectoryExt = record helper for TDirectory
  private
    class function DoGetFileSystemEntriesExt(const Path, SearchPattern: string;
        const SearchOption: TSearchOption): TSearchRecArray; static;
  public
    class function GetFileSystemEntriesExt(const Path,
      SearchPattern: string; SearchOption: TSearchOption): TSearchRecArray; static;
  end;
...

{ TDirectoryExt }

class function TDirectoryExt.DoGetFileSystemEntriesExt(const Path,
  SearchPattern: string; const SearchOption: TSearchOption): TSearchRecArray;
var
  PreCallback: TDirectoryExtSub.TDirectoryWalkProc;
  ResultArray: TSearchRecArray;
begin
  ResultArray := nil;
  PreCallback :=
    function (const Path: string; const FileInfo: TSearchRec): Boolean
    begin
      Result := True;

      if (FileInfo.Name <> '.') and (FileInfo.Name <> '..') then
      begin
        SetLength(ResultArray, Length(ResultArray) + 1);
        ResultArray[Length(ResultArray) - 1] := FileInfo;
      end;
    end;

  TDirectoryExtSub.WalkThroughDirectory(Path, SearchPattern, PreCallback, nil,
    SearchOption = TSearchOption.soAllDirectories);

  Result := ResultArray;
end;

class function TDirectoryExt.GetFileSystemEntriesExt(const Path,
  SearchPattern: string; SearchOption: TSearchOption): TSearchRecArray;
begin
  TDirectoryExtSub.CheckGetFileSystemEntriesParameters(Path, SearchPattern);

  Result := DoGetFileSystemEntriesExt(Path, SearchPattern, SearchOption);
end;

Open in new window


usage:
procedure TForm2.Button4Click(Sender: TObject);
var
  ResultArray: TSearchRecArray;
begin
  ResultArray := TDirectory.GetFileSystemEntriesExt('D:\Downloads', '*.pdf', TSearchOption.soAllDirectories);
  showmessage(IntToStr(Length(ResultArray)));
end;

Open in new window

1
Alfredo OrtegaAuthor Commented:
Thank you for your time and effort, Sinisa. Unfortunately, my level is about intermediate, and I have never used or created classes. I copied your solution and tried to create a unit using it. My first problem was to know the exact spot to insert those contents, since this is the skeleton of a unit created from scratch:

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, IOUtils;

type

  TForm1 = class(TForm)

  private
    { Private declarations }

  public
    { Public declarations }

  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

end.

Open in new window


Error messages from Delpji's editor (Delphi 2010 Architect):
1. Cannot resolve unit name System.IOUtils I deleted System. which fixed that problem
2. the editor showed the message Expected : but received FOR at line
TDirectoryExt = record helper for TDirectory

Open in new window

I commented out that line, since I din't know how to fix it after reading everything I found concerning record declaration.
And the rest of the error messages are, IMHO, caused because your lines of code are not inserted at the correct place. I know I'm asking for too much help, but would you be so kind as to post your contents (1st part of code) inserted into the 'skeleton'? That I would really appreciate.
0
Sinisa VukSoftware architectCommented:
Sorry, I use Xe10.2.2 for this example. Miss-reading your D2010 version. Will try to make another example.
1
Sinisa VukSoftware architectCommented:
Hope not to late here... But here is very simple example of (recursive) procedure:
uses ... Masks;

type
  TSearchRecArray = array of TSearchRec; //array...

 procedure DirectoryInfo(Path: String; SearchPattern: String; var ResultArray: TSearchRecArray);
var  
  rec : TSearchRec;
  FileOk: Boolean;
begin 
  Path := IncludeTrailingPathDelimiter(Path);
  if FindFirst(Path + '*.*', faAnyFile, rec) = 0 then
  begin
    repeat
      if (rec.Attr and faDirectory) <> 0 then
      begin
        // item is a directory
        if (rec.Name <> '.') and (rec.Name <> '..') then
        begin
          //go to sub-dir
          DirectoryInfo(Path + rec.Name, SearchPattern, ResultArray);
        end;
      end
      else
      begin
        //file?
        FileOk := True;
        if Length(SearchPattern) > 0 then
        begin
          FileOk := MatchesMask(rec.Name, SearchPattern);
        end;

        if FileOk then
        begin
          //file - add info about file...
          SetLength(ResultArray, Length(ResultArray) + 1);
          ResultArray[Length(ResultArray) - 1] := rec;
        end;
      end;
    until FindNext(rec) <> 0;
    FindClose(rec);
  end;
end;

function FileDateTimeToDateTime(const FileTime: TFileTime): TDateTime;
var
  SystemTime, LocalTime: TSystemTime;
begin
  if not FileTimeToSystemTime(FileTime, SystemTime) then
    RaiseLastOSError;

  if not SystemTimeToTzSpecificLocalTime(nil, SystemTime, LocalTime) then
    RaiseLastOSError;

  Result := SystemTimeToDateTime(LocalTime);
end;

Open in new window


usage:
procedure TForm2.Button1Click(Sender: TObject);
var
  ResultArray: TSearchRecArray;
begin
  SetLength(ResultArray, 0);
  DirectoryInfo('D:\Downloads', '*.pdf', ResultArray);
  showmessage('Found: ' + IntToStr(Length(ResultArray)));

  if Length(ResultArray) > 0 then
  begin
    //get info about first file
    ShowMessage('File: '+ResultArray[0].Name);
    ShowMessage('File created: '+DateTimeToStr(FileDateTimeToDateTime(ResultArray[0].FindData.ftCreationTime)));
    ShowMessage('File modified: '+DateTimeToStr(FileDateTimeToDateTime(ResultArray[0].FindData.ftLastWriteTime)));
    ShowMessage('File size: '+IntToStr(ResultArray[0].Size));
  end;
end;

Open in new window


Example does not use any newer classes or features.... And it is not need to....
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
Alfredo OrtegaAuthor Commented:
Thank you, I'll learn a lot with your answer, which brings some elements totally new to me.
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Delphi

From novice to tech pro — start learning today.