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?
 
Sinisa VukCommented:
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
 
Sinisa VukCommented:
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 VukCommented:
Sorry, I use Xe10.2.2 for this example. Miss-reading your D2010 version. Will try to make another example.
1
 
Alfredo OrtegaAuthor Commented:
Thank you, I'll learn a lot with your answer, which brings some elements totally new to me.
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.