Wyszukiwanie nazw plików w katalogu

Adam Boduch

Nie zrażaj się! Pod pojęciem wyszukiwania tekstu
kryje się fajna rzecz!! :)) Tak, tak nie jest to tak trudne jak mogłoby
się to wydawać na początek. Za chwilę przedstawię proces
przeszukiwania plików. W naszym programie chodziło będzie o
uzyskiwanie nazw wszystkich plików znajdujących się we wnętrzu
tegoż katalogu.

Najpierw stworzymy nową klasę - umieść więc w
sekcji "Interface" taki kod:

{
  Nowa klasa: zawiera ona w sekcji "private" zmienna wskazujaca na
  rekord przeszukujacy pliki, a funkcja sprawdza, czy ostatnim znakiem
  w zmiennej "Path" jest snak back-slash'a. Jezeli nie to dodaje go.
  W sekcji "public" znajduje sie procedura wyszukujaca pliki!
}
  TSearch = class
  private
    SR : TSearchRec;
    function IsSlashChar(Path : String) : String;
  public
    function FindIt(Dir : String; var Progress : Integer) : TStringList;
  end;

Pierwsza funkcja w sekcji "private": ustala ona, czy ścieżka, która została przekazana w zmiennej "APath" ma na końcu znak slash'a (""), czy tez nie. Deklaracja tej funkcji wygląda następująco:

function TSearch.IsSlashChar(Path: String): String;
begin
{
  Funkcja sprawdza, czy ostatnim znakiem zmiennej "Path" nie jest znak \. Jezeli nie jest to ten znak jest dodwany.
}
  if Path[Length(Path)] <> '' then
    Result := Path + '' else Result := Path;
end;

Tak jak mówiłem - na początku sprawdzany zostaje ostatni znak zmiennej "APath" - jeżeli nie jest to znak "" to dodawany jest on na końcu tej zmiennej i zwracany jako rezultat.

Dobra - teraz funkcja "FindIt". Delphi udostępnia dwa przydatne polecenia, które służą do wyszukiwania plików - są to "FindFirst", która rozpoczyna wyszukiwania plików.

FindFirst(Dir + '*.*', faAnyFile, SR); // odnajdz pliki

A więc szukanie plików następuje w katalogu, którego nazwa
kryje się pod zmienną "Dir". Do tej nazwy następuje dodana maska ( . oznacza wszystkie pliki ). Kolejnym parametrem tej funkcji jest typ plików, który ma być szukany - "faAnyFile" oznacza każdy plik. Ostatnim parametrem tej funkcji jest struktura typu "TSearchRec".

Funkcja "FindNext" natomiast daje polecenie do dalszego szukania pliku. To wszystko należy jeszcze wziąć w pętle "while" gdyż proces przeszukiwania ma być kontynuowany dopóki liczba znalezionych plików nie będzie się równać zeru. Cała funkcja wygląda tak:

function TSearch.FindIt(Dir: String; var Progress : Integer) : TStringList;
var
  Found : Integer; // zmienna przechowuje ilosc znalezionych plikow
begin
{
  Rezultatem tej funkcji jest zmienna typu "TStringList", ktora zawierac
  bedzie liste plikow, ktore zostaly odnalezione.
}
  Result := TStringList.Create; // stworz zmienna
  try
 // wywolaj funkcje, ktora sprawdza, czy na koncu zmiennej "Dir" jest znak ""
    Dir := IsSlashChar(Dir); 
    Found := FindFirst(Dir + '*.*', faAnyFile, SR); // odnajdz pliki
    while ( Found = 0 ) do //dopoki liczba znalezionych plikow nie bedzie rowna 0
    begin
{
  Ponizsza instrukcja odpowiada za to, zeby do listy znalezionych plikow nie
  dodawana byla nazwa '.' ani '..' ktore to oznaczaja, ze istnieje katalog
  wyzej.
}
      if (SR.Name <> '.') and (SR.Name <> '..') then
    // do listy "TStringList" dodaj nazwe znalezionego pliku  
      Result.Add(Dir +  SR.Name); 
      Found := FindNext(SR); // szukaj dalej...
    end;
  finally
    FindClose(SR); // zakoncz przeszukiwanie
  end;
{
  Ah. Bylbym zapomnial o opisaniu zmiennej "Process" w tej funkcji. Otoz  ta zmienna zawiera 'informacje' o stanie postepu w odnajdywaniu plikow.}
end;

Funkcja ta zwraca rezultat w postaci listy zawierającej nazwę
wszystkich znalezionych plików. Tak więc wywoływana zostaje pętla,
która zakończona jest dopiero wtedy gdy liczba znalezionych plików
nie równa się zeru. Następnie funkcja sprawdza, czy nazwa
znalezionego pliku nie równa się "." albo "..". Te dwie dziwne nazwy :) oznaczają to, że istnieje katalog wyżej. Nas to na razie nie obchodzi i dlatego nie chcemy, aby taka nazwa była dodana do listy znalezionych plików.

Wywołanie procedury i stworzenie tej klasy to taki kod:

procedure TMainForm.btnFindClick(Sender: TObject);
var
  Search : TSearch; // wskazuje na nowa klase
  I : Integer;
begin
  Search := TSearch.Create; // stworz klase
  try
// do komponentu dodawana jest lista z funkcji "FindIt"
    lblFindFiles.Items.Assign(Search.FindIt(DirList.Directory, i));
  // postep w odnajdywaniu pliku przestawiany jest na komponencie "progrssbar"
    prgProgress.Position := i; 
  finally
    Search.Free; // uwolnij zmienna
  end;
end;

Kod ten nie wymaga chyba większych komentarzy - "lblFindFiles"
to kontrolka typu "TListBox". Zresztą możesz ściągnąć sobie cały kod i zobaczyć jak to wygląda.

Cały listing prezentuje się w taki oto sposób:

(****************************************************************)
(*                                                              *)
(*      Example - programme searching files for Delphi 5        *)
(*     Copyright (c) 2001 by Service for programmers            *)
(*              Adam Boduch - Build: 23.03.2001                 *)
(*              HTTP://WWW.PROGRAMOWANIE.OF.PL                  *)
(*                E - mail:  boduch@poland.com                  *)
(*                                                              *)
(****************************************************************)      

unit MainFrm;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls, ComCtrls, FileCtrl;

type
  TMainForm = class(TForm)
    lblFindFiles: TListBox;
    btnFind: TButton;
    prgProgress: TProgressBar;
    DirList: TDirectoryListBox;
    procedure btnFindClick(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

{
  Nowa klasa: zawiera ona w sekcji "private" zmienna wskazujaca na
  rekord przeszukujacy pliki, a funkcja sprawdza, czy ostatnim znakiem
  w zmiennej "Path" jest snak back-slash'a. Jezeli nie to dodaje go.
  W sekcji "public" znajduje sie procedura wyszukujaca pliki!
}
  TSearch = class
  private
    SR : TSearchRec;
    function IsSlashChar(Path : String) : String;
  public
    function FindIt(Dir : String; var Progress : Integer) : TStringList;
  end;

var
  MainForm: TMainForm;

implementation

{$R *.DFM}

{ TSearch }

function TSearch.FindIt(Dir: String; var Progress : Integer) : TStringList;
var
  Found : Integer; // zmienna przechowuje ilosc znalezionych plikow
begin
{
  Rezultatem tej funkcji jest zmienna typu "TStringList", ktora zawierac
  bedzie liste plikow, ktore zostaly odnalezione.
}
  Result := TStringList.Create; // stworz zmienna
  try
 // wywolaj funkcje, ktora sprawdza, czy na koncu zmiennej "Dir" jest znak ""
    Dir := IsSlashChar(Dir); 
    Found := FindFirst(Dir + '*.*', faAnyFile, SR); // odnajdz pliki
    while ( Found = 0 ) do //dopoki liczba znalezionych plikow nie bedzie rowna 0
    begin
{
  Ponizsza instrukcja odpowiada za to, zeby do listy znalezionych plikow nie
  dodawana byla nazwa '.' ani '..' ktore to oznaczaja, ze istnieje katalog
  wyzej.
}
      if (SR.Name <> '.') and (SR.Name <> '..') then
   // do listy "TStringList" dodaj nazwe znalezionego pliku
      Result.Add(Dir +  SR.Name); 
      Found := FindNext(SR); // szukaj dalej...
    end;
  finally
    FindClose(SR); // zakoncz przeszukiwanie
  end;
{
  Ah. Bylbym zapomnial o opisaniu zmiennej "Process" w tej funkcji. Otoz  ta zmienna zawiera 'informacje' o stanie postepu w odnajdywaniu plikow.
}
end;

function TSearch.IsSlashChar(Path: String): String;
begin
{
  Funkcja sprawdza, czy ostatnim znakiem zmiennej "Path" nie jest znak "".
  Jezeli nie jest to ten znak jest dodwany.
}
  if Path[Length(Path)] <> '' then
    Result := Path + '' else Result := Path;
end;

procedure TMainForm.btnFindClick(Sender: TObject);
var
  Search : TSearch; // wskazuje na nowa klase
  I : Integer;
begin
  Search := TSearch.Create; // stworz klase
  try
// do komponentu dodawana jest lista z funkcji "FindIt"
    lblFindFiles.Items.Assign(Search.FindIt(DirList.Directory, i));
  // postep w odnajdywaniu pliku przestawiany jest na komponencie "progrssbar"
    prgProgress.Position := i; 
  finally
    Search.Free; // uwolnij zmienna
  end;
end;

end.

2 komentarzy

if Path[Length(Path)] <> '' then
Result := Path + '' else Result := Path;
Chyba powinno być:
if Path[Length(Path)] <> DirectorySeparator then
Result := Path + DirectorySeparator else Result := Path;
Przynajmniej tak jest we freepascalu, gdzie DirectorySeparator w Windows to '', a w Linuksie '/'.

Troche toto chaotyczne ;)