Solved

Locating files

Posted on 1998-07-28
11
372 Views
Last Modified: 2010-04-04
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!
0
Comment
Question by:Gal
  • 5
  • 4
  • 2
11 Comments
 
LVL 4

Accepted Solution

by:
BoRiS earned 50 total points
ID: 1358770
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
 
LVL 4

Expert Comment

by:erajoj
ID: 1358771
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
 
LVL 4

Expert Comment

by:erajoj
ID: 1358772
Whooah BoRiS! You're fast!
/// John
0
 
LVL 4

Expert Comment

by:erajoj
ID: 1358773
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
 
LVL 2

Author Comment

by:Gal
ID: 1358774
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
Threat Intelligence Starter Resources

Integrating threat intelligence can be challenging, and not all companies are ready. These resources can help you build awareness and prepare for defense.

 
LVL 4

Expert Comment

by:BoRiS
ID: 1358775
Gal

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

Later
BoRiS
0
 
LVL 2

Author Comment

by:Gal
ID: 1358776
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
 
LVL 4

Expert Comment

by:erajoj
ID: 1358777
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
 
LVL 2

Author Comment

by:Gal
ID: 1358778
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
 
LVL 4

Expert Comment

by:erajoj
ID: 1358779
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
 
LVL 2

Author Comment

by:Gal
ID: 1358780
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

Featured Post

Better Security Awareness With Threat Intelligence

See how one of the leading financial services organizations uses Recorded Future as part of a holistic threat intelligence program to promote security awareness and proactively and efficiently identify threats.

Join & Write a Comment

Introduction The parallel port is a very commonly known port, it was widely used to connect a printer to the PC, if you look at the back of your computer, for those who don't have newer computers, there will be a port with 25 pins and a small print…
In my programming career I have only very rarely run into situations where operator overloading would be of any use in my work.  Normally those situations involved math with either overly large numbers (hundreds of thousands of digits or accuracy re…
Internet Business Fax to Email Made Easy - With eFax Corporate (http://www.enterprise.efax.com), you'll receive a dedicated online fax number, which is used the same way as a typical analog fax number. You'll receive secure faxes in your email, fr…
This video demonstrates how to create an example email signature rule for a department in a company using CodeTwo Exchange Rules. The signature will be inserted beneath users' latest emails in conversations and will be displayed in users' Sent Items…

762 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

21 Experts available now in Live!

Get 1:1 Help Now