Solved

Directory and its Sub-Directories listing

Posted on 1997-06-10
3
457 Views
Last Modified: 2010-04-06


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
Comment
Question by:moose032797
  • 2
3 Comments
 

Accepted Solution

by:
brittain earned 50 total points
ID: 1336961
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
 

Author Comment

by:moose032797
ID: 1336962
>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
 

Expert Comment

by:brittain
ID: 1336963
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: Subnet Calculator

The subnet calculator helps you design networks by taking an IP address and network mask and returning information such as network, broadcast address, and host range.

One of a set of tools we're offering 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

Suggested Solutions

Title # Comments Views Activity
delphi exception 7 68
Communication Between RC4 Delphi <-> PHP 3 123
Open a URL with Internet Explorer in a new tab (not a new window) 1 121
Twebbrowser add css to the header 3 29
This article explains how to create forms/units independent of other forms/units object names in a delphi project. Have you ever created a form for user input in a Delphi project and then had the need to have that same form in a other Delphi proj…
Objective: - This article will help user in how to convert their numeric value become words. How to use 1. You can copy this code in your Unit as function 2. than you can perform your function by type this code The Code   (CODE) The Im…
This video shows how to quickly and easily add an email signature for all users on Exchange 2016. The resulting signature is applied on a server level by Exchange Online. The email signature template has been downloaded from: www.mail-signatures…

830 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