Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations TouchToneTommy on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

findfirst - findnext 1

Status
Not open for further replies.

lorife

Programmer
Nov 10, 2008
3
IT
Hi, i'm referring to the thread thread102-1418012.

please could you help me using sfindfirst to:

1) retrieve ALL directories and NO Files(hidden and system too, everything..)

2) retrieve ALL files and NO directories (hidden and system too, everything..)

i wish to retrieve exactly what i want, without use

"if ((SR.Attr and faDirectory) <> 0)"

how can i do?
 
Attributes are retrieved in a value with a set of flags that must be tested for to determine these things. There really isn't any way to get past that. Even the code from the thread does that.

1. This would be anything with a directory attribute. What you want is:

Code:
if (SR.Attr and faDirectory) = faDirectory

The code from the thread does it too, if you specify faDirectory

2. In this case you want anything that is NOT a directory. In sense you want this in your code when using faAnyfile as a filter attribute:

Code:
if (SR.Attr and faDirectory) <> faDirectory

There's really no way getting around interrogating the bits of the attribute value to find out these things.

----------
Measurement is not management.
 
It's been my experience that often even if you check the attribute when scanning folders with "*.*" it's just about
impossible to do stuff like add only folders to a list. I wasted about 6 hours trying to do it in Delphi 5 one day. I suspect FindFirst/FindNext is largely broken. Either that or there's some hidden trick like zeroing out the structure between each call or something. Sure doesn't work as expected. You might try one of those old "Undocumented Windows API" books if you can still find them.
 
thank you to everyone for the answer...i received just today the notification of both replies...

Anyways i think it's broken too! :)
 
FindFirst/FindNext is largely broken
I have to strongly disagree. I've been using TSearchRec and the FindFirst/FindNext successfully since Turbo Pascal, including Delphi versions 4,5 & 7 without any problem. It does require an understanding of parameter Attr and how it's logic works. All of which are explained in Delphi Help under topic "FindFirst". Below is a snippet from one of my more recent apps which uses it to search directories.
Code:
procedure TPastDueInvoices.FillDueCustList;
var
  sr: TSearchRec;
  rc: integer;
  DueCList: TStringList;
  OverDueList: TStringList;

  function InOverDueList(Customer: string): boolean;
  var i: integer;
  begin
    result:= false;
    for i:= 0 to OverDueList.Count - 1 do
      if pos(Customer, OverDueList[i]) > 0 then
        result:= true
  end;

begin
  DueCList:= TStringList.Create;
  OverDueList:= TStringList.Create;
  OverDueList.LoadFromFile(CollectionsFolder + 'OpenInvoices.txt');
  rc:= FindFirst(CollectionsFolder + '*.*', faDirectory, sr);
  try
    while rc = 0 do begin
      if (SR.Attr And faDirectory) = faDirectory  then
        if (sr.Name <> '.') and (sr.Name <> '..') then
          if InOverDueList(sr.Name) then
            DueCList.Add(sr.Name);
      rc:= FindNext(sr);
    end;
  finally
    FindClose(sr);
    Memo1.Lines.Assign(DueCList);
    FreeAndNil(DueCList);
    FreeAndNil(OverDueList);
  end;
end;
This may help you understand - The file attribute constants and their values are:
faReadOnly = 1
faHidden = 2
faSysFile = 4
faVolumeID = 8
faDirectory = 16
faArchive = 32
faAnyFile = 63

faReadOnly + faHidden + faSysFile + faVolumeID + faDirectory + faArchive = faAnyFile
or 1+2+4+8+16+32:=63;

So a hidden directory is: (2 and 16)
See also "Boolean operators" in Delphi Help.

HTH



Roo
Delphi Rules!
 
It's also worth noting that FindFirst must also include the directory to start looking in. You can also (or must) do recursive calls to search for sub-directories within each directory (or folder).

Roo
Delphi Rules!
 
hi, in the 1st topic I was talking about sfindfirst, not findfirst..which is a function Glenn9999 made.

however i know that fadirectory returns just directory...the problem is that there is no way to use findfirst to return just files (no directories) and you need to manually check the attributes using:

if (SR.Attr and faDirectory) <> faDirectory

What i mean is that if i have 1 file and 100 directory findfirst returns 101 results....unless you use sfindfirst (which works to retrieve just files but does not work if i want to retrieve just directories!)
 
findfirst isnt Glenns routine perhaps you have this the wrong way around.

Eitherway the code below manages to get just the folders using findfirst then build an explorer like tree.

This code based on a tutorial on using the treeview by Hugh Collingbrook (PCPlus magazine)

Code:
procedure TNetBackup.addSubDirs( rootDir : string;  Node : TTreeNode; Tree: integer);
var
  SearchRec: TSearchRec;
  Result : integer;
  NewNode : TTreeNode;
begin    // find first file, Result is 0 if successful
    Result := FindFirst(rootDir + '*.*', faDirectory, SearchRec);
    while Result = 0 do
    begin
       if browser.isDirectory(SearchRec) then
         begin  // if directory is found add it as a child of prev node in TreeView
            if tree = 0 then
               NewNode := Folders.Items.AddChild(Node, SearchRec.Name)
            else
               NewNode := DestFolders.Items.AddChild(Node, SearchRec.Name);

            NewNode.SelectedIndex := 1;
            if (browser.hasSubDirectories( rootDir + SearchRec.Name ) ) then
               NewNode.HasChildren := true;
         end; // then continue searching }
         Result := FindNext(SearchRec);
    end;
    FindClose(SearchRec);
    Node.AlphaSort;
end;

Isdirectory does indeed check the attribute field

Code:
function TBrowser.IsDirectory( sr : TSearchRec ) : boolean;
// test if current file is a directory
begin
   isDirectory := ((sr.Attr and faDirectory > 0)
                  and
                  (sr.Name <> '.') and (sr.Name <> '..'));
end;

Has subdirectories looks like this

Code:
function TBrowser.hasSubDirectories( d : string ) : boolean;
// test in the directory indicated by the string 'd' contains
// subdirectories. If so, return true.
var
  SearchRec: TSearchRec;
  SResult : integer;
  noSubDirFound : boolean;
begin    // find first file, Result is 0 if successful
    noSubDirFound := true;
    SResult := FindFirst(d + '\*.*', faDirectory, SearchRec);
    while ((SResult = 0) and (noSubDirFound)) do
       begin
          if isDirectory(SearchRec) then noSubDirFound := false;
          SResult := FindNext(SearchRec);
       end;
    FindClose(SearchRec);
    hasSubDirectories := (noSubDirFound = false);
end;
 
lorife said:
however i know that fadirectory returns just directory...the problem is that there is no way to use findfirst to return just files (no directories)

what is wrong with:

Result := FindFirst(rootDir + '*.*', 0, SearchRec);

which will search for all normal files (ie not having read-only, hidden or archive flag)

the inverse is true, if you want only directories, then you must test the faDirectory bit

/Daddy


-----------------------------------------------------
What You See Is What You Get
Never underestimate tha powah of tha google!
 
I can't speak for Glenn, but he may have discovered that wrapping every possible search scenario into a single process would be a bit overwhelming. Since he never posted a FAQ from this, I can only assume his attempt was incomplete. The best bit of information (IMO) in the thread you referenced was from Griffyn:
I also use the faAnyFile and post-filter.
The simplest approach is to write your own search, search for everything, and throw out what you don't want (post-filter) as Glenn pointed out in this thread.

My point was "it ain't broken" where "it" = FindFirst/FindNext.

Roo
Delphi Rules!
 
FYI - My last post was sitting 'un-sent' all night in my editor and was then sent this AM before reading any of the subsequent posts. Thank you 'unknown' for the star!

Roo
Delphi Rules!
 
I can't speak for Glenn, but he may have discovered that wrapping every possible search scenario into a single process would be a bit overwhelming. Since he never posted a FAQ from this, I can only assume his attempt was incomplete.

As was said in the original thread, thread102-1418012 , the only real incentive was to try and turn out something that would be a lot more predictable than the original Sysutils findfirst/findnext. You can see that from the initial question in the thread.

I ultimately did some playing around and came up with what was posted within that thread, which has "must have" processing as opposed to "may have" processing. I would guess that is the difference and results in (IMO the bug since DOS days) the specified attr being irrelevant.

As the question could come out in the posts: "What is the point of specifying attr, if I have to post-filter?"

The code was only posted to be something enlightening, not really anything for FAQ material (though I can make it that way with a couple of extra notes - see *). Sysutils is very similar - as you can see in the code, the Windows FindFirst/FindNext filters nothing. The code in the thread (and Sysutils for that matter) does that job. I would have to try it with the code I posted, but it might be interesting to see if it works by specifying "not faDirectory" for this OP's second question.

* - as most people code their own filters anyway, using faAnyFile, there is a lot of code in Sysutils.FindFirst and Sysutils.FindNext that gets run for basically no purpose. For this case, it's certainly better for efficiency sake to recode FindFirst/FindNext to simply call the Windows variants (without Attr in the function parms) and simply move the record data. This might be something to investigate if such a FAQ were to be written.

----------
Measurement is not management.
 
Since he never posted a FAQ from this

Done. More of a generic document on how FindFirst & FindNext works, but hopefully it will be interesting to someone.

faq102-7116

----------
Measurement is not management.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top