Recent

Author Topic: FindAllFiles  (Read 3561 times)

Zath

  • Sr. Member
  • ****
  • Posts: 391
FindAllFiles
« on: October 20, 2015, 12:52:07 am »
Hello.
Is there any way to show a running count of FindAllFiles as it trawls a drive ?
I wanted to add something like Label1.Caption:=IntToStr(Files.Count); into the example code below but it doesn't seem possible.
There's no great need to this, I'm just trying to learn various capabilities for future use.

Thanks.

Code: Pascal  [Select][+][-]
  1. uses
  2. ...
  3. fileutil
  4. ...
  5. var
  6.   PascalFiles: TStringList;
  7. begin
  8.   //No need to create the stringlist; the function does that for you
  9.   PascalFiles := FindAllFiles(LazarusDirectory, '*.pas;*.pp;*.p;*.inc', true); //find e.g. all pascal sourcefiles
  10.   try
  11.     showmessage(Format('Found %d Pascal source files',[PascalFiles.Count]));
  12.   finally
  13.     PascalFiles.Free;
  14.   end;
  15.  




molly

  • Hero Member
  • *****
  • Posts: 2330
Re: FindAllFiles
« Reply #1 on: October 20, 2015, 01:15:41 am »
Hi Zath,

I dunno if there's a better native lcl solution, but i know that user Bart has a unit named enumdirs that allows you to provide a callback routine so that you can f.e. update your label (might still require you to do a manual refresh though, or use processmessages).

Zath

  • Sr. Member
  • ****
  • Posts: 391
Re: FindAllFiles
« Reply #2 on: October 20, 2015, 01:37:12 am »
Hi Zath,

I dunno if there's a better native lcl solution, but i know that user Bart has a unit named enumdirs that allows you to provide a callback routine so that you can f.e. update your label (might still require you to do a manual refresh though, or use processmessages).

Thanks Molly, quite an interesting read, especially where it mentions Window's older 8.3 format and the errors created by ~1 etc.
I don't think I'll add it yet as I'm trying to learn the "official" functions at the mo.

molly

  • Hero Member
  • *****
  • Posts: 2330
Re: FindAllFiles
« Reply #3 on: October 20, 2015, 02:59:48 am »
np Zath.

In that case i don't know of any other solution than to use findfirst/findnext yourself and 'update' your label inside the loop. afaik there is no other (automatic) recursive filesearch that allows you to provide (visual) feedback.

The reason you're not able to update a counter or label is because the filesearch function doesn't give any feedback when it's running. You start it and when it ends it returns something useful -> this behavior is by design.

Hence why i mentioned enumdirs, as that does practically the same thing but allows the use of a callback routine.

You'll probably be able to find many other recursive filesearch-a-like solutions using findfirst/findnext (usually also encapsulated inside some sort of 'filesearch' function), that are made by others.

Alternatively you could copy-paste the source of the filesearch-function, program a counter inside it (storing it globally or directly in your form) so that you could perhaps run the routine asynchronously (or add processmessages inside the loop) and use the counter to give feedback to the user.

Only wanting to let you know that the standard/default filesearch function is not going to help you out there.

edit:
it just occurred to me that maybe you could do something with the notify events of the stringlist used to store the results of the filesearch function.

edit2:
i just noticed TFilesearcher inside fileutils.
« Last Edit: October 20, 2015, 03:12:34 am by molly »

molly

  • Hero Member
  • *****
  • Posts: 2330
Re: FindAllFiles
« Reply #4 on: October 20, 2015, 04:05:40 am »
regarding the notify events solution i suggested:

The function doesn't work as it creates the stringlist for you (so would override your events), but the procedure variant of FindAllFiles is able to work that way.

I've dropped a button and label on a form and added the notify event manually.
Code: Pascal  [Select][+][-]
  1.   TForm1 = class(TForm)
  2.     Button1: TButton;
  3.     Label1: TLabel;
  4.     procedure Button1Click(Sender: TObject);
  5.   private
  6.     { private declarations }
  7.     procedure pascalFileChange(Sender: TObject);
  8.     // procedure pascalFileChanging(Sender: TObject);
  9.   public
  10.     { public declarations }
  11.   end;
  12.  
  13. var
  14.   Form1: TForm1;
  15.  
  16. var
  17.   PascalFiles: TStringList;
  18.  

then i've added some code to the button click event:
Code: Pascal  [Select][+][-]
  1. procedure TForm1.Button1Click(Sender: TObject);
  2. begin                                          
  3.   pascalFiles := TStringList.Create;
  4.   pascalFiles.OnChange := @pascalFileChange;
  5.   // pascalFiles.OnChanging := @pascalFileChanging;;
  6.  
  7.   FileUtil.FindAllFiles(pascalFiles, 'Q:\Molly\', '*.*', true);
  8.  
  9.   pascalFiles.free;
  10. end;
  11.  

and in the change event:

Code: Pascal  [Select][+][-]
  1. procedure TForm1.pascalFileChange(Sender: TObject);
  2. Const
  3.   UpdateFrequency = 5;
  4. Var
  5.   Count : Integer;
  6. begin
  7.   count := pascalFiles.Count;
  8.   label1.Caption := IntToStr(Count);
  9.   if (count mod UpdateFrequency = 0) then application.ProcessMessages;
  10. end;          
  11.  

Which seems to work for me.

Roland57

  • Sr. Member
  • ****
  • Posts: 421
    • msegui.net
Re: FindAllFiles
« Reply #5 on: October 20, 2015, 08:29:44 am »
Which seems to work for me.

It works for me too. Nice solution!
My projects are on Gitlab and on Codeberg.

 

TinyPortal © 2005-2018