Link to home
Start Free TrialLog in
Avatar of Gal
Gal

asked on

Locating files

Hi,
I'm new to Delphi, and still using Delphi 2.0 (wow!),
I'm looking for a function to let me locate a file in the user's HD. FileSearch and FileExists both take parameters of directories, but there's no way to  look in subdirs as well.
since I don't know where or whether the app that created the files I need to locate has been installed, I need to look for them. anybody got an idea? this is quite urgent!
ASKER CERTIFIED SOLUTION
Avatar of BoRiS
BoRiS

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
This is one of the many ways.
It searches using regular expression in any UNC directory, and puts all matching filenames in a TStrings list:

function FindFiles( sDir, sMask: string; rgsFiles: TStrings; bRecursively: Boolean ): Integer;
var
  SR: TSearchRec;
begin
  Result := 0;
  if not Assigned( rgsFiles ) then Exit;
  if sDir[ Length( sDir )] <> '\' then AppendStr( sDir, '\' ); // fix dir
  if FindFirst( sDir + sMask, faAnyFile, SR ) = 0 then repeat
    if ( SR.Attr and faDirectory ) <> faDirectory then rgsFiles.Add( sDir+SR.Name );
  until FindNext( SR ) <> 0;
  FindClose( SR );
  // recursive part...
  if bRecursively then begin
    if FindFirst( sDir + '*.*', faAnyFile, SR ) = 0 then repeat
      if (( SR.Attr and faDirectory ) = faDirectory ) and ( SR.Name[1] <> '.' )
      then FindFiles( sDir+SR.Name+'\', sMask, rgsFiles, bRecursively );
    until FindNext( SR ) <> 0;
    FindClose( SR );
  end;
  Result := rgsFiles.Count;
end;

Usage:
  FindFiles( 'c:\', '*.txt', ListBox1.Items, True );
or
  MyStrings := TStringList.Create;
  cLog := FindFiles( '\\server\logs\', '*.log', MyStrings, False );
etc...

I hope this will work in D2!

/// John
 
Whooah BoRiS! You're fast!
/// John
Appendix:
  the faAnyFile declared in Delphi might not be enough, hence:

const
  faNormal     = $00000080;
  faTemporary  = $00000100;
  faCompressed = $00000800;
  faAnyFileEx  = faReadOnly or faHidden or faSysFile or faVolumeID or faDirectory or faArchive or faNormal or faTemporary or faCompressed;

Just replace all occurances of faAnyFile with faAnyFileEx.
Without this, all files will NOT be found!

/// John
Avatar of Gal
Gal

ASKER

Thanks, BoRiS, erajoj.

I will try it out this evening and let you know how it went.
Thanks!

(BTW, BoRiS, I understand you're almost a neighbour - Tel-Aviv? I'm in Herzeliya. (Israel).
Gal

No sorry...  I stay in South Africa...

Later
BoRiS
Avatar of Gal

ASKER

OK, erajoj, I implemented that piece of code you gave me, but I still don't really get it - I mean, I went through the logic, and it does work (I tested it too, of course). what I don't get yet is how to be able to get the File's full name (UNC) to a string-type var to be able to figure out its path, (extractFileDir), its date (FileAge) etc., to figure out if I need to replace it with a new one, append to it, and so on.
Thanks
Gal
Hi,
There are of course, as always, several ways to attack this problem. The files in the list are in full name format, provided the sDir parameter is a full UNC directory name.

To get a path out of the list you do as usual:
  sPath := MyList[ 0 ]; // for example
To get the file time stamp, you just call FileGetDate:
  FileDate := FileGetDate( sPath );
To convert the date to TDateTime format:
  dtFile := FileDateToDateTime( FileDate );

Another way to do this is to modify the search function:

type
  PFileData = ^TFileData;
  TFileData = record
    Path, Name: string;
    Time : TDateTime;
    Size, Attr : Integer;
  end;

  ...

function NewFindFiles( sDir, sMask: string; rgFileData: TList; bRecursively: Boolean ): Integer;
var
  SR: TSearchRec;
  pfd: PFileData;
begin
  Result := 0;
  if not Assigned( rgsFiles ) then Exit;
  if sDir[ Length( sDir )] <> '\' then AppendStr( sDir, '\' ); // fix dir
  if FindFirst( sDir + sMask, faAnyFile, SR ) = 0 then repeat
    if ( SR.Attr and faDirectory ) <> faDirectory then begin
      New( pfd );
      rgFileData.Add( pfd );
      with pfd^ do begin
        Name := SR.Name;
        Path := sDir;
        Size := SR.Size;
        Attr := SR.Attr;
        Time := FileDateToDateTime( SR.Time );
      end;
    end;
  until FindNext( SR ) <> 0;
  FindClose( SR );
  // recursive part...
  if bRecursively then begin
    if FindFirst( sDir + '*.*', faAnyFile, SR ) = 0 then repeat
      if (( SR.Attr and faDirectory ) = faDirectory ) and ( SR.Name[1] <> '.' )
      then FindFiles( sDir+SR.Name+'\', sMask, rgsFiles, bRecursively );
    until FindNext( SR ) <> 0;
    FindClose( SR );
  end;
  Result := rgsFiles.Count;
end;


Then, to use it:
 
var
  myfiledata: PFileData;
  MyFileDataList: TList;
  ...
 
  if ( NewFindFiles( 'c:\', '*.txt', MyFileDataList, True ) > 0 ) then begin
    myfiledata := MyFileDataList[ 0 ];
    with myfiledata^ do begin
      if ( ( Date-Time ) > 7 ) then ... /// more than a week old!
      FullFilename := Path + Name;
    end;
  end;

You just have to clean up after you. MyFileDataList.Clear or MyFileDataList.Free is NOT enough. You still have data on your heap, so:

  for iIndex := 0 to MyFileDataList.Count - 1 do
    Dispose( PFileData( MyFileDataList[ iIndex ] ) );
  MyFileDataList.Free;

Thats about it.

/// John
Avatar of Gal

ASKER

Hi erajoj.
I just noticed that they routed the point for this question you answered for me to BoRiS. I don't know why, but I guess it's because something I did or didn't do?
Anyway, the points clearly belong to you, so, if there's a way to reroute them, please let me know so I can do that
Sorry for the inconvenience.
Gal.

Hi Gal.
Don't be sorry!
The points are not important at all if you're content with the answer!
BoRiS gave you a good answer and deserves the points.

/// John
Avatar of Gal

ASKER

Well, thanks any way to both of you.
This session really got me going with my program here.
Thanks a lot and keep up the good work.

Gal.