Solved

Directory and its Sub-Directories listing

Posted on 1997-06-10
3
444 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 Trending Threat Insights Every Day

Enhance your security with threat intelligence from the web. Get trending threat insights on hackers, exploits, and suspicious IP addresses delivered to your inbox with our free Cyber Daily.

Join & Write a Comment

Hello everybody This Article will show you how to validate number with TEdit control, What's the TEdit control? TEdit is a standard Windows edit control on a form, it allows to user to write, read and copy/paste single line of text. Usua…
Introduction I have seen many questions in this Delphi topic area where queries in threads are needed or suggested. I know bumped into a similar need. This article will address some of the concepts when dealing with a multithreaded delphi database…
This video gives you a great overview about bandwidth monitoring with SNMP and WMI with our network monitoring solution PRTG Network Monitor (https://www.paessler.com/prtg). If you're looking for how to monitor bandwidth using netflow or packet s…
This demo shows you how to set up the containerized NetScaler CPX with NetScaler Management and Analytics System in a non-routable Mesos/Marathon environment for use with Micro-Services applications.

705 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

Need Help in Real-Time?

Connect with top rated Experts

17 Experts available now in Live!

Get 1:1 Help Now