Recent

Author Topic: Reading a directory list of files into an array of string;  (Read 16523 times)

JLWest

  • Hero Member
  • *****
  • Posts: 1293
Reading a directory list of files into an array of string;
« on: January 21, 2018, 03:58:39 am »
I'm trying to read the list of files in a directory into and array of string.
Seem to be having some trouble with an internal error.

Anybody figured this one out?
FPC 3.2.0, Lazarus IDE v2.0.4
 Windows 10 Pro 32-GB
 Intel i7 770K CPU 4.2GHz 32702MB Ram
GeForce GTX 1080 Graphics - 8 Gig
4.1 TB

Handoko

  • Hero Member
  • *****
  • Posts: 5131
  • My goal: build my own game engine using Lazarus
Re: Reading a directory list of files into an array of string;
« Reply #1 on: January 21, 2018, 04:01:32 am »
Show us your code, so we can point out where you did wrong.

Thaddy

  • Hero Member
  • *****
  • Posts: 14206
  • Probably until I exterminate Putin.
« Last Edit: January 21, 2018, 08:45:12 am by Thaddy »
Specialize a type, not a var.

Handoko

  • Hero Member
  • *****
  • Posts: 5131
  • My goal: build my own game engine using Lazarus
Re: Reading a directory list of files into an array of string;
« Reply #3 on: January 21, 2018, 08:50:45 am »
Here I wrote an example how to use FindFirst and FindNext:

Code: Pascal  [Select][+][-]
  1. unit Unit1;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes, SysUtils, Forms, Controls, Dialogs, StdCtrls, Dos;
  9.  
  10. type
  11.  
  12.   { TForm1 }
  13.  
  14.   TForm1 = class(TForm)
  15.     btnBrowse: TButton;
  16.     btnShow: TButton;
  17.     cbxHidden: TCheckBox;
  18.     cbxFolder: TCheckBox;
  19.     edtDirectory: TEdit;
  20.     Label1: TLabel;
  21.     Label2: TLabel;
  22.     SelectDirectoryDialog1: TSelectDirectoryDialog;
  23.     procedure btnBrowseClick(Sender: TObject);
  24.     procedure btnShowClick(Sender: TObject);
  25.     procedure FormCreate(Sender: TObject);
  26.   end;
  27.  
  28. var
  29.   Form1: TForm1;
  30.  
  31. implementation
  32.  
  33. {$R *.lfm}
  34.  
  35. { TForm1 }
  36.  
  37. procedure TForm1.FormCreate(Sender: TObject);
  38. begin
  39.   edtDirectory.Text := ExtractFileDir(ParamStr(0));
  40. end;
  41.  
  42. procedure TForm1.btnBrowseClick(Sender: TObject);
  43. begin
  44.   if not(SelectDirectoryDialog1.Execute) then Exit;
  45.   edtDirectory.Text := SelectDirectoryDialog1.FileName;
  46. end;
  47.  
  48. procedure TForm1.btnShowClick(Sender: TObject);
  49. var
  50.   ListOfFiles   : array of string;
  51.   ListOfFolders : array of string;
  52.   SearchResult  : SearchRec;
  53.   Attribute     : Word;
  54.   Message       : string;
  55.   i             : Integer;
  56. begin
  57.  
  58.   SetLength(ListOfFiles, 0);
  59.   SetLength(ListOfFolders, 0);
  60.  
  61.   // Prepare attribute
  62.   Attribute := archive or readonly;
  63.   if cbxHidden.Checked then
  64.     Attribute := Attribute or hidden;
  65.  
  66.   // List the files
  67.   FindFirst (edtDirectory.Text+DirectorySeparator+'*.*', Attribute, SearchResult);
  68.   while (DosError = 0) do
  69.   begin
  70.     SetLength(ListOfFiles, Length(ListOfFiles) + 1); // Increase the list
  71.     ListOfFiles[High(ListOfFiles)] := SearchResult.Name; // Add it at the end of the list
  72.     FindNext(SearchResult);
  73.   end;
  74.   FindClose(SearchResult);
  75.  
  76.   // List the sub folders
  77.   if (cbxFolder.Checked) then
  78.   begin
  79.     Attribute := Attribute or faDirectory;
  80.     FindFirst (edtDirectory.Text+DirectorySeparator+'*.*', Attribute, SearchResult);
  81.     while (DosError = 0) do
  82.     begin
  83.       if (SearchResult.Attr and directory) <> 0 then
  84.       begin
  85.         SetLength(ListOfFolders, Length(ListOfFolders) + 1); // Increase the list
  86.         ListOfFolders[High(ListOfFolders)] := SearchResult.Name; // Add it at the end of the list
  87.       end;
  88.       FindNext(SearchResult);
  89.     end;
  90.     FindClose(SearchResult);
  91.   end;
  92.  
  93.   // Show the result
  94.   Message := 'The directory contains ' + Length(ListOfFiles).ToString + ' file(s).' + #13;
  95.   for i := Low(ListOfFiles) to High(ListOfFiles) do
  96.     Message := Message + ListOfFiles[i] + #13;
  97.   if (cbxFolder.Checked) then
  98.   begin
  99.     Message := Message + #13 + 'And ' + Length(ListOfFolders).ToString + ' folder(s).' + #13;
  100.     for i := Low(ListOfFolders) to High(ListOfFolders) do
  101.       Message := Message + ListOfFolders[i] + #13;
  102.   end;
  103.   ShowMessage(Message);
  104.  
  105. end;
  106.  
  107. end.

Note:

I use FindFirst and FindNext from unit Dos (not from FileUtil SysUtils).
https://www.freepascal.org/docs-html/rtl/dos/findfirst.html

Because of some technical issues, the show folder feature does not work correctly on Linux. (Haven't tried FileUtil SysUtils, maybe it will work correctly)
« Last Edit: January 21, 2018, 04:41:43 pm by Handoko »

dbannon

  • Hero Member
  • *****
  • Posts: 2786
    • tomboy-ng, a rewrite of the classic Tomboy
Re: Reading a directory list of files into an array of string;
« Reply #4 on: January 21, 2018, 01:24:05 pm »
I have been using the FileUtil version, works reliably on Linux, Windows and Mac - like this

Code: Pascal  [Select][+][-]
  1. var
  2.     Info : TSearchRec;
  3. begin                      
  4.         .....
  5.         if FindFirst(WorkingDir + '*.note', faAnyFile and faDirectory, Info)=0 then begin
  6.                 repeat
  7.                         DoSomething(WorkingDir, Info.Name);
  8.                 until FindNext(Info) <> 0;
  9.         end;
  10.         FindClose(Info);
  11. end;
(untested but pretty much whats in my tested code)
If cross platform is desirable, avoid things like #13 and DosError. Constants like "LineEnding" and PathDelim are useful. In the above, "WorkingDir"  contains the path and must end with an appropriate PathDelim, AppendPathDelim(Dir) does the trick.
Lazarus 3, Linux (and reluctantly Win10/11, OSX Monterey)
My Project - https://github.com/tomboy-notes/tomboy-ng and my github - https://github.com/davidbannon

ASerge

  • Hero Member
  • *****
  • Posts: 2223
Re: Reading a directory list of files into an array of string;
« Reply #5 on: January 21, 2018, 01:27:10 pm »
Because of some technical issues, the show folder feature does not work correctly on Linux. (Haven't tried FileUtil, maybe it will work correctly)
Test the example with FileUtil for Linux. The code looks simpler.
As in your example, only
Code: Pascal  [Select][+][-]
  1. procedure TForm1.btnShowClick(Sender: TObject);
  2. var
  3.   ListOfFiles: TStringList;
  4.   ListOfFolders: TStringList;
  5.   Attributes: Integer;
  6.   Message: string;
  7. begin
  8.   Attributes := faReadOnly;
  9.   if cbxHidden.Checked then
  10.     Attributes := Attributes or faHidden;
  11.   ListOfFiles := TStringList.Create;
  12.   try
  13.     FileUtil.FindAllFiles(ListOfFiles, edtDirectory.Text, '*', False, Attributes);
  14.     ListOfFiles.Insert(0, Format('The directory contains %d file(s).', [ListOfFiles.Count]));
  15.     Message := ListOfFiles.Text;
  16.   finally
  17.     ListOfFiles.Free;
  18.   end;
  19.   if cbxFolder.Checked then
  20.   begin
  21.     ListOfFolders := TStringList.Create;
  22.     try
  23.       FileUtil.FindAllDirectories(ListOfFolders, edtDirectory.Text, False);
  24.       ListOfFolders.Insert(0, Format('And %d folders(s).', [ListOfFolders.Count]));
  25.       Message := Message + ListOfFolders.Text;
  26.     finally
  27.       ListOfFolders.Free;
  28.     end;
  29.   end;
  30.   ShowMessage(Message)
  31. end;

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 11383
  • FPC developer.
Re: Reading a directory list of files into an array of string;
« Reply #6 on: January 21, 2018, 01:28:19 pm »
I use FindFirst and FindNext from unit Dos (not FileUtil).
https://www.freepascal.org/docs-html/rtl/dos/findfirst.html

Not recommended, better use the sysutils versions.

dbannon

  • Hero Member
  • *****
  • Posts: 2786
    • tomboy-ng, a rewrite of the classic Tomboy
Re: Reading a directory list of files into an array of string;
« Reply #7 on: January 21, 2018, 01:36:06 pm »
Please note, in my post above, I should have said "sysutils' version, not "fileutils" version.
David
Lazarus 3, Linux (and reluctantly Win10/11, OSX Monterey)
My Project - https://github.com/tomboy-notes/tomboy-ng and my github - https://github.com/davidbannon

Handoko

  • Hero Member
  • *****
  • Posts: 5131
  • My goal: build my own game engine using Lazarus
Re: Reading a directory list of files into an array of string;
« Reply #8 on: January 21, 2018, 02:53:53 pm »
Yep, my fault. I searched the web and found FindFirst from unit Dos, I didn't pay attention that it also available from SysUtils. I knew it only after finished writing the code. Yes, FindFirst and FindNext from SysUtils are better.

JLWest

  • Hero Member
  • *****
  • Posts: 1293
Re: Reading a directory list of files into an array of string;
« Reply #9 on: January 21, 2018, 03:42:07 pm »
Here I wrote an example how to use FindFirst and FindNext:

I downloaded Loaded project and compile and ran.

Works Great.
Now I need to go thru it and  figure it out so I can adapt it for my project.

Thanks
FPC 3.2.0, Lazarus IDE v2.0.4
 Windows 10 Pro 32-GB
 Intel i7 770K CPU 4.2GHz 32702MB Ram
GeForce GTX 1080 Graphics - 8 Gig
4.1 TB

JLWest

  • Hero Member
  • *****
  • Posts: 1293
Re: Reading a directory list of files into an array of string;
« Reply #10 on: January 21, 2018, 03:44:41 pm »
Yep, my fault. I searched the web and found FindFirst from unit Dos, I didn't pay attention that it also available from SysUtils. I knew it only after finished writing the code. Yes, FindFirst and FindNext from SysUtils are better.

So I can delete DOS from the USES clause.

Not a good idea. Compiler gave me a bunch of errors. I think the cause is SearchRec
SysUtils must have an equivalent but called something else.

Looks like SearchRec, DosErro and TRawbyteSearchRec are all having prolems.



Compile Project, Target: project1.exe: Exit code 1, Errors: 17
unit1.pas(52,19) Error: Identifier not found "SearchRec"
unit1.pas(52,28) Error: Error in type definition
unit1.pas(62,16) Error: Identifier not found "archive"
unit1.pas(62,27) Error: Identifier not found "readonly"
unit1.pas(64,31) Error: Identifier not found "hidden"
unit1.pas(67,81) Error: Call by var for arg no. 3 has to match exactly: Got "<erroneous type>" expected "TRawbyteSearchRec"
unit1.pas(68,10) Error: Identifier not found "DosError"
unit1.pas(71,52) Error: Illegal qualifier
unit1.pas(72,26) Error: Call by var for arg no. 1 has to match exactly: Got "<erroneous type>" expected "TRawbyteSearchRec"
unit1.pas(74,25) Error: Call by var for arg no. 1 has to match exactly: Got "<erroneous type>" expected "TRawbyteSearchRec"
unit1.pas(80,83) Error: Call by var for arg no. 3 has to match exactly: Got "<erroneous type>" expected "TRawbyteSearchRec"
unit1.pas(81,12) Error: Identifier not found "DosError"
unit1.pas(83,24) Error: Illegal qualifier
unit1.pas(83,33) Error: Identifier not found "directory"
unit1.pas(86,60) Error: Illegal qualifier
unit1.pas(88,28) Error: Call by var for arg no. 1 has to match exactly: Got "<erroneous type>" expected "TRawbyteSearchRec"
unit1.pas(90,27) Error: Call by var for arg no. 1 has to match exactly: Got "<erroneous type>" expected "TRawbyteSearchRec"
« Last Edit: January 21, 2018, 03:54:57 pm by JLWest »
FPC 3.2.0, Lazarus IDE v2.0.4
 Windows 10 Pro 32-GB
 Intel i7 770K CPU 4.2GHz 32702MB Ram
GeForce GTX 1080 Graphics - 8 Gig
4.1 TB

Handoko

  • Hero Member
  • *****
  • Posts: 5131
  • My goal: build my own game engine using Lazarus
Re: Reading a directory list of files into an array of string;
« Reply #11 on: January 21, 2018, 04:15:52 pm »
My code requires unit Dos, if you want to use FindFirst and FindNext from unit SysUtils you should try the example from dbannon or ASerge (FindAllFiles).

You still can use my code (that uses unit Dos) without any issue if your program runs only on Windows. I tested it on both Windows 7 and Linux. On Windows, it works without any issue. On Linux it works correctly for listing files but it fails to list directories. If your program doesn't need to list directory, it can be use on Linux too.

Some reading materials if you want to improve your programming skills:

My code uses Dynamic Array, read more:
http://wiki.freepascal.org/Dynamic_array
https://www.freepascal.org/docs-html/rtl/system/setlength.html
https://www.freepascal.org/docs-html/rtl/system/low.html
https://www.freepascal.org/docs-html/rtl/system/high.html

I used ParamStr and ExtractFileDir to get the application's directory:
https://www.freepascal.org/docs-html/rtl/system/paramstr.html
https://www.freepascal.org/docs-html/rtl/sysutils/extractfiledir.html

File attributes used in unit Dos:
https://www.freepascal.org/docs-html-3.0.0/rtl/dos/fileattributes.html

dbannon mentioned some useful things (good for build cross platform app):
https://www.freepascal.org/docs-html/rtl/system/lineending.html
https://www.freepascal.org/docs-html/rtl/sysutils/pathdelim.html

ASerge's code uses FindAllFiles and TStringList:
http://wiki.freepascal.org/findallfiles
https://www.freepascal.org/docs-html/rtl/classes/tstringlist.html
https://www.freepascal.org/docs-html/rtl/sysutils/format.html
« Last Edit: January 21, 2018, 04:33:48 pm by Handoko »

JLWest

  • Hero Member
  • *****
  • Posts: 1293
Re: Reading a directory list of files into an array of string;
« Reply #12 on: January 21, 2018, 06:57:40 pm »
nit Unit1;
{$mode objfpc}{$H+}
interface
uses
    Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls;
type
    { TForm1 }
    TForm1 = class(TForm)
        Button1: TButton;
        procedure Button1Click(Sender: TObject);
    private

    public

    end;

var
    Form1: TForm1;

implementation

{$R *.lfm}

{ TForm1 }

procedure TForm1.Button1Click(Sender: TObject);
     var
      ListOfFiles: TStringList;
      ListOfFolders: TStringList;
      Attributes: Integer;
      Message: string;
      cbx1 : integer;
    begin
      cbx1 :=1;
      Attributes := faReadOnly;
      if cbx1 = 1 then
        Attributes := Attributes or faHidden;
      ListOfFiles := TStringList.Create;
      try
        FileUtil.FindAllFiles(ListOfFiles, edtDirectory.Text, '*', False, Attributes);
        ListOfFiles.Insert(0, Format('The directory contains %d file(s).', [ListOfFiles.Count]));
        Message := ListOfFiles.Text;
      finally
        ListOfFiles.Free;
      end;
      if cbx1 = 1 then
      begin
        ListOfFolders := TStringList.Create;
        try
          FileUtil.FindAllDirectories(ListOfFolders, edtDirectory.Text, False);
          ListOfFolders.Insert(0, Format('And %d folders(s).', [ListOfFolders.Count]));
          Message := Message + ListOfFolders.Text;
        finally
          ListOfFolders.Free;
        end;
      end;
      ShowMessage(Message)
end;

end.
Compile Project, Target: project1.exe: Exit code 1, Errors: 2, Warnings: 1
unit1.pas(44,45) Warning: Symbol "faHidden" is not portable
unit1.pas(47,44) Error: Identifier not found "edtDirectory"
unit1.pas(57,54) Error: Identifier not found "edtDirectory"

Can't find edtDirectory. Is this by any chance a listbox on the form named editDirectory?

The procedure was supplied by Aserge.
FPC 3.2.0, Lazarus IDE v2.0.4
 Windows 10 Pro 32-GB
 Intel i7 770K CPU 4.2GHz 32702MB Ram
GeForce GTX 1080 Graphics - 8 Gig
4.1 TB

Handoko

  • Hero Member
  • *****
  • Posts: 5131
  • My goal: build my own game engine using Lazarus
Re: Reading a directory list of files into an array of string;
« Reply #13 on: January 21, 2018, 07:08:52 pm »
To be able to compile ASerge's example, you need to combine it with my code, what you need to do is to replace the things inside procedure TForm1.btnShowClick (of mine) with ASerger's code.

RAW

  • Hero Member
  • *****
  • Posts: 868
Re: Reading a directory list of files into an array of string;
« Reply #14 on: January 21, 2018, 07:30:26 pm »
Quote
Can't find edtDirectory. Is this by any chance a listbox on the form named editDirectory?
Would be a fabulous name for a listbox....  :D
Windows 7 Pro (x64 Sp1) & Windows XP Pro (x86 Sp3).

 

TinyPortal © 2005-2018