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.
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 ;)