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!
LVL 2
GalAsked:
Who is Participating?
 
BoRiSConnect With a Mentor Commented:
gal

here is a code snippet to do just that can't remember were I got it from...I think it might have been JimBob...

procedure FileFind(StartingDirectory, FileName: string; FilesFound: TStringList);

  procedure SearchTree;
  var
    SearchRec: TSearchRec;
    DosError: integer;
    dir: string;
  begin
    GetDir(0, dir);
    if dir[length(dir)] <> '\' then dir := dir + '\';
    DosError := FindFirst(FileName, 0, SearchRec);
    while DosError = 0 do begin
      try
        FilesFound.add(dir + SearchRec.name);
      except
        on EOutOfResources do begin
          ShowMessage('Too many files.');
          abort;

        end;
      end;
      DosError := FindNext(SearchRec);
    end;
    {Now that we have all the files we need, lets go to a subdirectory.}
    DosError := FindFirst('*.*', faDirectory, SearchRec);
    while DosError = 0 do begin
      {If there is one, go there and search.}
      if ((SearchRec.attr and faDirectory = faDirectory) and
        (SearchRec.name <> '.') and (SearchRec.name <> '..')) then begin
        ChDir(SearchRec.name);
        SearchTree; {Time for the recursion!}
        ChDir('..'); {Down one level.}

      end;
      DosError := FindNext(SearchRec); {Look for another subdirectory}
    end;
  end; {SearchTree}

begin
  FilesFound.clear;
  ChDir(StartingDirectory);
  SearchTree;
end; {FileFind}

procedure TForm1.Button1Click(Sender: TObject);
var
  t: TStringList;
begin
  t := TStringList.create;
  FileFind(edit2.text, edit1.text, t);
  listbox1.items.assign(t);
  t.free;
end;

end.

just check what the form needs, buttons listbox etc...

Later
BoRiS
0
 
erajojCommented:
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
 
0
 
erajojCommented:
Whooah BoRiS! You're fast!
/// John
0
Free Tool: Subnet Calculator

The subnet calculator helps you design networks by taking an IP address and network mask and returning information such as network, broadcast address, and host range.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

 
erajojCommented:
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
0
 
GalAuthor Commented:
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).
0
 
BoRiSCommented:
Gal

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

Later
BoRiS
0
 
GalAuthor Commented:
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
0
 
erajojCommented:
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
0
 
GalAuthor Commented:
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.

0
 
erajojCommented:
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
0
 
GalAuthor Commented:
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.

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.