We help IT Professionals succeed at work.

We've partnered with Certified Experts, Carl Webster and Richard Faulkner, to bring you two Citrix podcasts. Learn about 2020 trends and get answers to your biggest Citrix questions!Listen Now

x

check if files exist in folders (FindFirst bug?)

WallaceAdrian
on
Medium Priority
748 Views
Last Modified: 2010-08-05
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 }
Comment
Watch Question

Top Expert 2004

Commented:
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 ;-)

Author

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

Top Expert 2004

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

meikl ;-)
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....
Top Expert 2004

Commented:
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 ;-)

Author

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.

Commented:
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.

Commented:
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 :)
Commented:
PAQed with points refunded (125)

GranMod
Community Support Moderator

Not the solution you were looking for? Getting a personalized solution is easy.

Ask the Experts
Access more of Experts Exchange with a free account
Thanks for using Experts Exchange.

Create a free account to continue.

Limited access with a free account allows you to:

  • View three pieces of content (articles, solutions, posts, and videos)
  • Ask the experts questions (counted toward content limit)
  • Customize your dashboard and profile

*This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

OR

Please enter a first name

Please enter a last name

8+ characters (letters, numbers, and a symbol)

By clicking, you agree to the Terms of Use and Privacy Policy.