Recent

Author Topic: How to interject a file action function within the FindAllFiles function  (Read 15174 times)

Gizmo

  • Hero Member
  • *****
  • Posts: 831
Hi

I am trying to recurse a given directory and hash each file found.

I have learnt that TFileSearcher is the way to go with this and, having read http://lazarus.firmos.at/index.php?topic=11200.0 have the following code that very nicely allows the user to select the directory and the content is outputted to a memo box.

Code: [Select]
procedure TForm1.Button3Click(Sender: TObject);
var
  DirToHash : string;
  sl :TStringList;
begin
  if SelectDirectoryDialog1.Execute then
    begin
    DirSelectedField.Caption := SelectDirectoryDialog1.FileName;
    DirToHash := SelectDirectoryDialog1.FileName;
    if DirPathExists(DirToHash) then                      // Check selected dir exists.
                                      
    begin
    sl := TStringList.Create;
      try
        sl := FindAllFiles(DirToHash, '*.*', True);      // Finds all files and puts in list
        Memo1.Lines.Assign(sl);

      // SOMEHOW NEED TO HASH FILES HERE...

      finally
        sl.Free;
      end;
    end;
  end;          

However, because FindAllFiles outputs the finished result to s1, I can't intervene and ask it to hash each file, while it's at it. I think I need to open each file (using 'reset') to do this.

In other words, I want my output in the memo box to be both the filename and the accompanying file hash.

Also, as s1 is a string list, a need to open the actual file fo reading and hashing. MDHash can hash a file without opening it into memory, but I'm not sure how to use that in this context?

I know the syntax for hashing a single file from an OpenDialog no problem but I don't know how to interject that into the listing above. Can anyone help?

Many thanks

Ted
« Last Edit: February 26, 2011, 03:06:40 pm by tedsmith »

Bart

  • Hero Member
  • *****
  • Posts: 5575
    • Bart en Mariska's Webstek
Re: How to interject a file action function within the FindAllFiles function
« Reply #1 on: February 26, 2011, 06:11:34 pm »
Take a look at this component of mine.
http://home-1.tiscali.nl/~knmg0017/software/fpc_laz/enumdirs.zip

It traverses directories (recusive if you want) and you can supply a callbackfunction that can process the files (and dirs) it enumerates.

The EnumDirs component has a dependency on this http://home-1.tiscali.nl/~knmg0017/software/fpc_laz/extmasks.zip component, so you'll need to download that one as well.
(You can comment out the fpc_patches in the uses clause of EnumDirs)

Both components are licensed under the modified LGPL license.

Bart

Leledumbo

  • Hero Member
  • *****
  • Posts: 8819
  • Programming + Glam Metal + Tae Kwon Do = Me
Re: How to interject a file action function within the FindAllFiles function
« Reply #2 on: February 26, 2011, 10:09:42 pm »
If you see the docs, there are two event handler for TFileSearcher. And what you need is OnFileFound, assign it with a method conforming TFileFoundEvent. e.g. (this is just the way I prefer to do, you can simply assign the OnFileFound property if you like):
Code: Delphi  [Select][+][-]
  1. interface
  2.  
  3. type
  4.   TFileHasher = class(TFileSearcher)
  5.   private
  6.     procedure HashFile(FileIterator: TFileIterator);
  7.   public
  8.     constructor Create;
  9.   end;
  10.  
  11. implementation
  12.  
  13. procedure TFileHasher.HashFile(FileIterator: TFileIterator);
  14. begin
  15.   // hash the file here
  16. end;
  17.  
  18. constructor TFileHasher.Create;
  19. begin
  20.   inherited;
  21.   FOnFileFound := @HashFile;
  22. end;
  23.  
  24. end.
  25.  
Now you can create a TFileHasher instance and call Search method to hash all files conforming to given Search arguments.
« Last Edit: February 27, 2011, 01:00:25 am by Leledumbo »

Gizmo

  • Hero Member
  • *****
  • Posts: 831
Re: How to interject a file action function within the FindAllFiles function
« Reply #3 on: February 27, 2011, 12:31:15 am »
Many thanks for that example. I appreciate your time.

Having had a go, I have at last accepted that I need to go away and read up more on Free Pascal. All this procedure X, assign Y, Method Z, TThis and TThat is confusing the hell out of me. I need to find a really basic "This is how a pascal program works...." resource and then I'll come back to your example and try to implement it.

(PS - do you know of any such "Idiots guide to Free Pascal"? :-) )

Ted

Leledumbo

  • Hero Member
  • *****
  • Posts: 8819
  • Programming + Glam Metal + Tae Kwon Do = Me
Re: How to interject a file action function within the FindAllFiles function
« Reply #4 on: February 27, 2011, 01:04:42 am »
Quote
do you know of any such "Idiots guide to Free Pascal"?
This website is great, it's not really Free Pascal specific, but more Pascal in general. Look for any Delphi books, such as Mastering Delphi 7. Most of the concept applies to Free Pascal. And last but not least, the documentation (esp. Pascal Language Reference Guide) itself.

Gizmo

  • Hero Member
  • *****
  • Posts: 831
Re: How to interject a file action function within the FindAllFiles function
« Reply #5 on: February 28, 2011, 10:51:40 pm »
I have found the website very useful! Thanks for pointing it out to me. I am so far about 75% through it and have created a crib-sheet style reference page to help me.

I am about to start on the Object Orientated bit!

In the meantime, would you be able to simplify your above example at all? I realise it is probably very simple to you anyway, but I am struggling with getting my head round a few bits still. For example, why use the @ sign on line 21 (@HashFile;  ) and what does inherited; do??

The FP4S website is covering lots and adding to my knowledge gaps, but I don't recall it talking about these bits? 

Leledumbo

  • Hero Member
  • *****
  • Posts: 8819
  • Programming + Glam Metal + Tae Kwon Do = Me
Quote
In the meantime, would you be able to simplify your above example at all?
No problem.
Code: [Select]
 
type 
  TForm1 = class(TForm) 
  private
    procedure HashFile(FileIterator: TFileIterator);
  public
    // I assume you want to do it on a button click
    procedure Button1Click(Sender: TObject);
  end;
 
implementation 
 
procedure TForm1.HashFile(FileIterator: TFileIterator); 
begin 
  // hash the file here 
end; 
 
procedure TForm1.Button1Click(Sender: TObject);
var
  FS: TFileSearcher;
begin
  FS := TFileSearcher.Create; // create TFileSearcher instance
  FS.OnFileFound := @HashFile; // assign the handler
  FS.Search; // do the search, hashing all found files
  FS.Free; // destroy the instance
end; 
 
end.
Quote
why use the @ sign on line 21 (@HashFile;  ) and what does inherited; do??
In objfpc mode (see {$mode objfpc} on top of your form's unit), when assigning procedural variables (commonly used as event handlers) you have to use @ operator to differ it from a call. inherited (without anything else) is a way to call parent class' method of the same name and expecting the same (number and type of) arguments.

Gizmo

  • Hero Member
  • *****
  • Posts: 831
Leledumbo

I just wanted to thank you for taking the time to help me. My program now works! And I've learnt a lot since your initial reply to me and I've added my own bits pieces (a TStringGrid and all sorts) to enhance the overall thing.

You got me going again when I nearly gave up! Thankyou!

For the benefit of others :

Code: [Select]

 if DirPathExists(DirToHash) then      // Check selected dir exists. DirPathExists from fileutil.pas
                                            // Now lets recursively find each file,
                                            // and ask HashFile to hash each one found
        begin
        FS := TFileSearcher.Create;         // create TFileSearcher instance
        FS.OnFileFound := @HashFile;        // assign the HashFile handler
        FS.Search(DirToHash, '*.*', True);  // do the search, hashing all found files
        FS.Free;                            // destroy the instance
        end
      else
        begin
        ShowMessage('Invalid directory selected');
        end;           

======

procedure TForm1.HashFile(FileIterator: TFileIterator);                         
var                                                                             
  NameOfFileToHash, fileHashValue : string;                                     
  FI : TFileIterator;                      //File Iterator class               
  SG : TStringGrid;                                                             
                                                                               
begin                                                                           
   FI := TFileIterator.Create;                                                 
   NameOfFileToHash := (FileIterator.FileName);                                 
   fileHashValue := SHA1Print(SHA1File(NameOfFileToHash));  //MDPrint(MDFile(Nam
   // Col 0 is FileCounter. Col 1 is File Name. Col 2 is Hash                   
   SG := TStringGrid.Create(self);                                             
   StringGrid1.rowcount:= FileCounter+1;                                       
   StringGrid1.Cells[0,FileCounter] := IntToStr(FileCounter);                   
   Stringgrid1.Cells[1,FileCounter] := NameOfFileToHash;                       
   Stringgrid1.Cells[2,FileCounter] := fileHashValue;                           
   FileCounter := FileCounter+1;                                               
   SG.Free;                                                                     
   FI.Free;                                                                     
                                                                               
end;                         
                                                   
Ted
« Last Edit: March 04, 2011, 06:49:38 pm by tedsmith »

 

TinyPortal © 2005-2018