?
Solved

check if files exist in folders (FindFirst bug?)

Posted on 2006-04-06
10
Medium Priority
?
707 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 }
0
Comment
Question by:WallaceAdrian
9 Comments
 
LVL 27

Expert Comment

by:kretzschmar
ID: 16391131
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
 
LVL 2

Author Comment

by:WallaceAdrian
ID: 16391512
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
 
LVL 27

Expert Comment

by:kretzschmar
ID: 16391570
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
Free Tool: ZipGrep

ZipGrep is a utility that can list and search zip (.war, .ear, .jar, etc) archives for text patterns, without the need to extract the archive's contents.

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

 
LVL 2

Expert Comment

by:alijunior
ID: 16393431
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
 
LVL 27

Expert Comment

by:kretzschmar
ID: 16393943
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
 
LVL 2

Author Comment

by:WallaceAdrian
ID: 16399483
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
 
LVL 1

Expert Comment

by:HanZulu
ID: 16415568
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
 
LVL 1

Expert Comment

by:Kristao
ID: 16511663
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
 

Accepted Solution

by:
GranMod earned 0 total points
ID: 16949444
PAQed with points refunded (125)

GranMod
Community Support Moderator
0

Featured Post

Free Tool: Port Scanner

Check which ports are open to the outside world. Helps make sure that your firewall rules are working as intended.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

The uses clause is one of those things that just tends to grow and grow. Most of the time this is in the main form, as it's from this form that all others are called. If you have a big application (including many forms), the uses clause in the in…
In this tutorial I will show you how to use the Windows Speech API in Delphi. I will only cover basic functions such as text to speech and controlling the speed of the speech. SAPI Installation First you need to install the SAPI type library, th…
This video tutorial shows you the steps to go through to set up what I believe to be the best email app on the android platform to read Exchange mail.  Get the app on your phone: The first step is to make sure you have the Samsung Email app on your …
There may be issues when you are trying to access Outlook or send & receive emails or due to Outlook crash which leads to corrupt or damaged PST file. To eliminate the corruption from your PST file, you need to repair the corrupt Outlook PST file. U…
Suggested Courses
Course of the Month4 days, 5 hours left to enroll

601 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