• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 495
  • Last Modified:

Directory and its Sub-Directories listing



If I want to get a list of all sub-directories immediately
below a given directory.  

At the moment, I am currently using code like :

     IF FindFirst (in_dir_path + '*.*',
          (faDirectory), SearchRec) = 0 then
     begin
          IF DirectoryExists (in_dir_path + SearchRec.Name) Then
             in_out_Listbox.Items.Add (in_dir_path + SearchRec.Name + '\');
     end;

     While FindNext (SearchRec) = 0 do
     begin
          IF DirectoryExists (in_dir_path + SearchRec.Name) Then
             in_out_Listbox.Items.Add (in_dir_path + SearchRec.Name + '\');
     end;

The real pain is that the FindFirst / FindNext return all files
+ directories - hence the need for the DirectoryExists
check before adding the item to the listbox.

This isn't what I want - because for directories with many hundreds
of files and only a few sub-directories, this takes a few seconds.

Is there any way to list just the directories ?

I have also written code that extends the above to list
all sub-directories of a given directory - not just the directories
immediately below the given directory.

Does anybody have some good fast code to do this ?
0
moose032797
Asked:
moose032797
  • 2
1 Solution
 
brittainCommented:
Couple things:

1.  FindFirst() and FindNext() are just wrappers around the WINAPI FindFirstFile() and FindNextFile().  The optimal solution would be to write your own FindFirstDir(), etc.

2.  Small performance improvement can be gained by checking the Attr property of SearchRec rather than calling DirectoryExists().

3.  Larger performance improvement:  Build a string list in memory within your loop, then afterwards Assign the string list to the control.  The reason for this is each Items.Add() call sends a Windows message to the control, very slow.
0
 
moose032797Author Commented:
>The optimal solution would be to write your own
>FindFirstDir(), etc.

OK, but this relies on me being able to find the first dir and
then the next.

As I said above, I need to know how to do this in Delphi.

Moose
0
 
brittainCommented:
As always, all things are possible with the source.  This is what I meant by write your own.  FindMatchingFile() and FindFirstDir() are straight out of the SYSUTILS.PAS.  (I added the Dir, of course).  The only change is marked by [srb] in the code.  Note, I didn't have to check FindNext()!

This is the quick solution.  These should probably be improved to better exist with SYSUTILS.PAS (i.e. FindMatchingFile() was a local function to the SYSUTILS.PAS unit).

function FindMatchingFile(var F: TSearchRec): Integer;
var
  LocalFileTime: TFileTime;
begin
  with F do
  begin
    while FindData.dwFileAttributes and ExcludeAttr <> 0 do
      if not FindNextFile(FindHandle, FindData) then
      begin
        Result := GetLastError;
        Exit;
      end;
    FileTimeToLocalFileTime(FindData.ftLastWriteTime, LocalFileTime);
    FileTimeToDosDateTime(LocalFileTime, LongRec(Time).Hi,
      LongRec(Time).Lo);
    Size := FindData.nFileSizeLow;
    Attr := FindData.dwFileAttributes;
    Name := FindData.cFileName;
  end;
  Result := 0;
end;


function FindFirstDir(const Path: string; Attr: Integer;
  var F: TSearchRec): Integer;
const
  //[srb]faSpecial = faHidden or faSysFile or faVolumeID or faDirectory;
  //[srb] Added the faAnyFile constant to this exclusion mask!
  faSpecial = faAnyFile or faHidden or faSysFile or faVolumeID or faDirectory;
begin
  F.ExcludeAttr := not Attr and faSpecial;
  F.FindHandle := FindFirstFile(PChar(Path), F.FindData);
  if F.FindHandle <> INVALID_HANDLE_VALUE then
  begin
    Result := FindMatchingFile(F);
    if Result <> 0 then FindClose(F);
  end else
    Result := GetLastError;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  f : TSearchRec;
  lt : TStringList;

begin
  lt := TStringList.Create;
  try
//    if (0 = FindFirst( 'c:\winnt\*.*', (faDirectory), f )) then begin
    if (0 = FindFirstDir( 'c:\winnt\*.*', (faDirectory), f )) then begin
      lt.Add(f.name);
//      while (0 = FindNext( f )) do
      while (0 = FindNext( f )) do
        lt.Add(f.name);

      ListBox1.Items.Assign( lt );
    end;
  finally
    lt.free;
  end;
end;

0

Featured Post

Free Tool: IP Lookup

Get more info about an IP address or domain name, such as organization, abuse contacts and geolocation.

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.

  • 2
Tackle projects and never again get stuck behind a technical roadblock.
Join Now