Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to Search a File through all the SubDirectories in Delphi

Tags:

delphi

I have implemented this code in Delphi, it will search for the File or the name given but it omits searching all the subdirectories. How can this be done?

Code:

 if FindFirst(filePath,faAnyFile,searchResult)=0 then
  try
    repeat
    lbSearchResult.Items.Append(searchResult.Name);

    until FindNext(searchResult)<>0
  except
  on e:Exception do
  ShowMessage(e.Message);
  end; //try ends
  FindClose(searchResult); 
like image 695
CyprUS Avatar asked Jun 30 '11 14:06

CyprUS


4 Answers

If you don't need threading, the simplest way is this:

procedure TForm1.AddAllFilesInDir(const Dir: string);
var
  SR: TSearchRec;
begin
  if FindFirst(IncludeTrailingBackslash(Dir) + '*.*', faAnyFile or faDirectory, SR) = 0 then
    try
      repeat
        if (SR.Attr and faDirectory) = 0 then
          ListBox1.Items.Add(SR.Name)
        else if (SR.Name <> '.') and (SR.Name <> '..') then
          AddAllFilesInDir(IncludeTrailingBackslash(Dir) + SR.Name);  // recursive call!
      until FindNext(Sr) <> 0;
    finally
      FindClose(SR);
    end;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  ListBox1.Items.BeginUpdate;
  AddAllFilesInDir('C:\Users\Andreas Rejbrand\Documents\Aweb');
  ListBox1.Items.EndUpdate;
end;
like image 89
Andreas Rejbrand Avatar answered Oct 16 '22 18:10

Andreas Rejbrand


With Delphi XE and up, you can have a look at IOUtils.pas:

TDirectory.GetFiles('C:\', '*.dll', TSearchOption.soAllDirectories);
like image 41
Uwe Raabe Avatar answered Oct 16 '22 19:10

Uwe Raabe


The simplest way is:

uses
  DSiWin32;

DSiEnumFilesToStringList('c:\somefolder\file.name', 0, ListBox1.Items, true, true);

DSiWin32 is a free Delphi library.

like image 4
gabr Avatar answered Oct 16 '22 19:10

gabr


When i need to do trickslike override protected methods i tend to use a generic solution to the problem... i do a hack to the class.

Here is how to do it with TDirectoryListbox.

On every Form you need to use this hacked TDirectoryListbox just add unitTDirectoryListbox_WithHiddenAndSystemFolders to interface uses, that way the form will use the hacked TDirectoryListbox.

Create a file called unitTDirectoryListbox_WithHiddenAndSystemFolders.pas on your proyect folder.

Put this text inside that file (i will explain later what i have done):

unit unitTDirectoryListbox_WithHiddenAndSystemFolders;

interface

uses
    Windows
   ,SysUtils
   ,Classes
   ,FileCtrl
   ;

type TDirectoryListbox=class(FileCtrl.TDirectoryListbox)
   private
     FPreserveCase:Boolean;
     FCaseSensitive:Boolean;
   protected
     function ReadDirectoryNames(const ParentDirectory:String;DirectoryList:TStringList):Integer;
     procedure BuildList;override;
   public
     constructor Create(AOwner:TComponent);override;
     destructor Destroy;override;
     property PreserveCase:Boolean read FPreserveCase;
     property CaseSensitive:Boolean read FCaseSensitive;
end;

implementation

constructor TDirectoryListbox.Create(AOwner:TComponent);
begin
     inherited Create(AOwner);
end;

destructor TDirectoryListbox.Destroy;
begin
     inherited Destroy;
end;

function TDirectoryListbox.ReadDirectoryNames(const ParentDirectory:String;DirectoryList:TStringList):Integer;
var
  TheCount,Status:Integer;
  SearchRec:TSearchRec;
begin
     TheCount:=0;
     Status:=FindFirst(IncludeTrailingPathDelimiter(ParentDirectory)+'*.*',faDirectory or faHidden or faSysFile,SearchRec);
     try
        while 0=Status
        do begin
                if faDirectory=(faDirectory and SearchRec.Attr) 
                then begin
                          if   ('.'<>SearchRec.Name)
                            and
                               ('..'<>SearchRec.Name)
                          then begin
                                    DirectoryList.Add(SearchRec.Name);
                                    Inc(TheCount);
                               end;
                     end;
                Status:=FindNext(SearchRec);
           end;
     finally
            FindClose(SearchRec);
     end;
     ReadDirectoryNames:=TheCount;
end;

procedure TDirectoryListBox.BuildList;
var
  TempPath: string;
  DirName: string;
  IndentLevel, BackSlashPos: Integer;
  VolFlags: DWORD;
  I: Integer;
  Siblings: TStringList;
  NewSelect: Integer;
  Root: string;
begin
  try
    Items.BeginUpdate;
    Items.Clear;
    IndentLevel := 0;
    Root := ExtractFileDrive(Directory)+'\';
    GetVolumeInformation(PChar(Root), nil, 0, nil, DWORD(i), VolFlags, nil, 0);
    FPreserveCase := VolFlags and (FS_CASE_IS_PRESERVED or FS_CASE_SENSITIVE) <> 0;
    FCaseSensitive := (VolFlags and FS_CASE_SENSITIVE) <> 0;
    if (Length(Root) >= 2) and (Root[2] = '\') then
    begin
      Items.AddObject(Root, OpenedBMP);
      Inc(IndentLevel);
      TempPath := Copy(Directory, Length(Root)+1, Length(Directory));
    end
    else
      TempPath := Directory;
    if (Length(TempPath) > 0) then
    begin
      if AnsiLastChar(TempPath)^ <> '\' then
      begin
        BackSlashPos := AnsiPos('\', TempPath);
        while BackSlashPos <> 0 do
        begin
          DirName := Copy(TempPath, 1, BackSlashPos - 1);
          if IndentLevel = 0 then DirName := DirName + '\';
          Delete(TempPath, 1, BackSlashPos);
          Items.AddObject(DirName, OpenedBMP);
          Inc(IndentLevel);
          BackSlashPos := AnsiPos('\', TempPath);
        end;
      end;
      Items.AddObject(TempPath, CurrentBMP);
    end;
    NewSelect := Items.Count - 1;
    Siblings := TStringList.Create;
    try
      Siblings.Sorted := True;
        { read all the dir names into Siblings }
      ReadDirectoryNames(Directory, Siblings);
      for i := 0 to Siblings.Count - 1 do
        Items.AddObject(Siblings[i], ClosedBMP);
    finally
      Siblings.Free;
    end;
  finally
    Items.EndUpdate;
  end;
  if HandleAllocated then
    ItemIndex := NewSelect;
end;

end.

Now i explain what i have done:

  • By adding unitTDirectoryListbox_WithHiddenAndSystemFolders to interface uses i make the form to use the modified (aka, hacked) component.
  • I started by copying protected method called ReadDirectoryNames (the one that needs a modification), i copy it from unit FileCtrl and then i edit that copy on my own unit to fix the problem (not showing Hidden folders, neither System folders); the trick is to edit the call to FindFirst by adding after faDirectory the part or faHidden or faSysFile, i also change SlashSep to IncludeTrailingPathDelimiter (avoid some extra references, etc) and also do a reformat (indexing, etc) so i can see that method is the one i had modified.
  • Then i follow things missing... like BuildList, that one i just simply copy it from unit FileCtrl without any modification (if not copied the hack does not work, since the call to ReadDirectoryNames is inside BuildList).
  • Then i copy the declaration of FPreserveCase and FCaseSensitive and their property declarations (they are used inside BuildList method).
  • That is it, now the modified TDirectoryListBox will see hidden and system folders

Hope this helps others, this way you can have both TDirectoryListBox (original one and modified one) at same time (but not on same form, sorry) on your project, without modifing VCL at all.

P.D.: Someone with extra knowledge maybe is able to add properties to configure if it must show or not hidden and/or system folders as an improvement, it must not be very difficoult, two private boolean variables and their corresponding property declaration with read and write methods... i did not do it since i would like to add not only such two, also SymLinks, etc (search for faSymLink on unit SysUtils and see how many there are, a lot of work to add them all), sorry for any inconvenience for that.

like image 1
Anonymous Avatar answered Oct 16 '22 19:10

Anonymous