check if files exist in folders (FindFirst bug?)

hi experts,

I wrote a utility to monitor a list of folders and check if they contain files but it doesn't always work.  (Is there a better way of doing this?)

Sample folders:
  C:\empty         // no files
  C:\non_empty   // contains "new document.txt"

Test cases:
If my folder list contains in this order:  C:\non_empty;   C:\empty;  then FindFirst works.
If my folder list contains in this order:  C:\empty;  C:\non_empty;  then FindFirst returns false for both cases.

Am I doing something really stupid?  I've tried this code (and variations) on 2 different machines (OS = WinXP)

source code below.

function FolderIsEmpty(aFolder : string) : Boolean;
var
  LSearchRec: TSearchRec;
  LSearchFileName : string;
begin
  AddTrailingBackSlash(aFolder);  // adds one if not found
  LSearchFileName := aFolder+'*.*';
  if FindFirst(LSearchFileName, faAnyFile - faDirectory, LSearchRec) = 0 then
  begin
    Result := False;
    FindClose(LSearchRec);  // free memory:  only call this if successful; harmful otherwise
  end
  else
    Result := True;
end;
 
   ...
    for i := 0 to LFolderList.Count -1 do   // stringlist of folders
    begin
      if Trim(LFolderList[i]) <> '' then
      begin
        if not FolderIsEmpty(LFolderList[i]) then
        begin
          Result := Result + 'Files found in folder:  '+LFolderList[i]+#13#10;
        end;
      end;
    end; { end for }
LVL 2
WallaceAdrianAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

kretzschmarCommented:
try this change

function FolderIsEmpty(aFolder : string) : Boolean;
var
  LSearchRec: TSearchRec;
  LSearchFileName : string;
begin
  AddTrailingBackSlash(aFolder);  // adds one if not found
  LSearchFileName := aFolder+'*.*';
  result := (FindFirst(LSearchFileName, faAnyFile - faDirectory, LSearchRec) = 0);  
  FindClose(LSearchRec);  // free memory allways
end;

//not sure about this part faAnyFile - faDirectory
//i would use faAnyFile and not faDirectory

meikl ;-)
0
WallaceAdrianAuthor Commented:
hi meikl,

I had already tried the:
  FindClose(LSearchRec);  // free memory allways
but i've read that this can cause NT workstations to lock up, so i haven't adopted it.

>//not sure about this part faAnyFile - faDirectory
>//i would use faAnyFile and not faDirectory
If I use faAnyFile then I'll need to handle finding the "." and ".." recs that are found.  However, this still doesn't fix the problem since the 2nd call to FindFirst still returns the wrong result.

Adrian

0
kretzschmarCommented:
currently i have no delphi enviroment available here,
so i cannot reproduce, but will try this evening, if this happens to me too

meikl ;-)
0
Keep up with what's happening at Experts Exchange!

Sign up to receive Decoded, a new monthly digest with product updates, feature release info, continuing education opportunities, and more.

alijuniorCommented:
Hi Adrian...

Try this:

function FolderIsEmpty(aFolder : string) : Boolean;
var
  SR: TSearchRec;
begin

  Result := True;

  aFolder := IncludeTrailingPathDelimiter( aFolder );

  //Primeiro busca os arquivos do diretório
  if FindFirst( aFolder + '*', faAnyFile - faDirectory, SR ) = 0 then
  begin
    Result := False;
    FindClose( SR );
  end;

end;

Best regards....
0
kretzschmarCommented:
usual i cannot reproduce this, works properly

my testcase:

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Memo1: TMemo;
    ListBox1: TListBox;
    ListBox2: TListBox;
    Button2: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

function FolderIsEmpty(aFolder : string) : Boolean;
var
  LSearchRec: TSearchRec;
  LSearchFileName : string;
begin
  //AddTrailingBackSlash(aFolder);  // adds one if not found
  LSearchFileName := aFolder+'*.*';
  if FindFirst(LSearchFileName, faAnyFile - faDirectory, LSearchRec) = 0 then
  begin
    Result := False;
    FindClose(LSearchRec);  // free memory:  only call this if successful; harmful otherwise
  end
  else
    Result := True;
end;


procedure TForm1.Button1Click(Sender: TObject);
var i : integer;
begin
  for i := 0 to ListBox1.Items.Count -1 do   // stringlist of folders
    begin
      if Trim(ListBox1.Items[i]) <> '' then
      begin
        if not FolderIsEmpty(ListBox1.Items[i]) then
        begin
          memo1.lines.add('Files found in folder:  '+ListBox1.Items[i]);
        end;
      end;
    end; { end for }

end;

procedure TForm1.Button2Click(Sender: TObject);
var i : integer;
begin
  for i := 0 to ListBox2.Items.Count -1 do   // stringlist of folders
    begin
      if Trim(ListBox2.Items[i]) <> '' then
      begin
        if not FolderIsEmpty(ListBox2.Items[i]) then
        begin
          memo1.lines.add('Files found in folder:  '+ListBox2.Items[i]);
        end;
      end;
    end; { end for }

end;

end.

could be a problem with your
AddTrailingBackSlash-function,
i don't have it, thats why i have commented it out

meikl ;-)
0
WallaceAdrianAuthor Commented:
Thanks for the comments but i've managed to solve it (after many tests!).

alijunior: thanks for "IncludeTrailingPathDelimiter( aFolder );"  i didn't know about this routine.

It was a really stupid error and was data dependant;
This was the original call:
      if Trim(LFolderList[i]) <> '' then
      begin
        if not FolderIsEmpty(LFolderList[i]) then
the folder list contained spaces so i needed to add
  FolderIsEmpty(Trim(LFolderList[i]));

I realised something was wrong when i tested this way:
button1click;
begin
  FolderIsEmpty('c:\empty\');
  FolderIsEmpty('c:\non_empty\');
end;

button1click;
begin
  FolderIsEmpty('c:\non_empty\');
  FolderIsEmpty('c:\empty\');
end;

I then thought it was the array passing problem (but saw that meikl called it the same way i did)  ... then i used a local variable ... only then did i realise it was the Trim that was missing.    *doh*

Thanks for the help guys.
0
HanZuluCommented:
It seems like it should work.

the only suspicious routine is

 AddTrailingBackSlash(aFolder);  // adds one if not found

check what this does exactly and print the strings upon entering your internal routine. you may find your search string is not as you expect.

the rest look fine and works.

0
KristaoCommented:
Hi

Can't see where is the problem. Here is nice peace of code with litle recursy <don't realy know how to spell that wrld, but in code you will see what i think>

procedure scan_dir(dir: string; var Files:TStringList);
var
  spr: TSearchRec;
begin
  if findfirst(dir + '*.*', faAnyFile, spr) = 0 then
  begin
    repeat
      if ((spr.Name <> '.') and (spr.Name <> '..')) then begin
        if spr.Attr = 16 then //if its folder
        begin
          scan_dir(dir + spr.Name + '\');
        end
        else begin
          Files.add(spr.Name);
        end;
      end;
    until FindNext(spr) <> 0;
    FindClose(spr);
  end;
end;

this code will return all files in specific folder and in subfolders if there is subfolders :)

root folder-
               |
                Folder
                        Folder-------------
                        Bethoven.mp3    |
                                                |
                                                 Folder
                                                 MyDoc.doc

So if you will check root folder with this procedure you will get beck TStrigList with 2 files Bethoven.mpr and MyDoc.doc

In your case we can litle bit change the code

function scan_dir(dir: string):boolean;
var
  spr: TSearchRec;
begin
  result:=false;
  if findfirst(dir + '*.*', faAnyFile, spr) = 0 then
  begin
    repeat
      if ((spr.Name <> '.') and (spr.Name <> '..')) then begin
         result:=true;
         break;
      end;
    until FindNext(spr) <> 0;
    FindClose(spr);
  end;
end;

Regards
Kristao :)
0
GranModCommented:
PAQed with points refunded (125)

GranMod
Community Support Moderator
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Delphi

From novice to tech pro — start learning today.