Поиск
файлов
В качестве примера
использования рекурсии рассмотрим задачу поиска файлов. Пусть нужно получить
список всех файлов, например, с расширением bmp, которые находятся в указанном
пользователем каталоге и во всех подкаталогах этого каталога.
Словесно алгоритм обработки
каталога может быть представлен так:
1. Вывести список всех
файлов удовлетворяющих критерию запроса.
2. Если в каталоге
есть подкаталоги, то обработать каждый из этих каталогов.
Приведенный алгоритм
(его блок-схема представлена на рис. 12.4) является рекурсивным: для того чтобы
обработать подкаталог, процедура обработки текущего каталога должна вызвать
сама себя.
Рис. 12.4. Рекурсивный
алгоритм поиска файлов
Вид диалогового окна
программы приведен на рис. 12.5, текст — в листинге 12.3.
Поле Файл (Edit1)
используется для ввода имени искомого файла или маски (для поиска файлов одного
типа). Имя каталога, в котором нужно выполнить поиск, можно ввести непосредственно
в поле Папка или выбрать из стандартного диалогового окна Обзор папок,
которое появляется в результате щелчка на кнопке Папка. Окно Обзор
папок (рис. 12.6) выводит на экран стандартная функция Seiectoirectory.
Следует обратить внимание, что имя каталога, который используется в диалоговом
окне Обзор папок в качестве корневого, должно передаваться функции SeiectDirectory
как Строка WhideChar. Для Преобразования обычной строки в строку WideChar использована
функция StringToWhideChar.
Рис. 12.5. Окно
программы Поиск файлов
Рис. 12.6. Диалоговое
окно Обзор папок появляется в результате щелчка на кнопке Папка
Основную работу выполняет
рекурсивная функция Find. У функции Find один-единственный параметр — структура
searchRec, которая используется функциями FindFirst и FindNext для поиска соответственнопервого
и следующего файла, удовлетворяющего критерию поиска. Следует обратить внимание
на то, как осуществляется перебор каталогов в текущем каталоге. Если текущий
каталог не корневой, то помимо обычных, то есть имеющих имя, в каталоге есть
еще два каталога: .. и ., которые обозначают каталог предыдущего уровня. Эти
два каталога не обрабатываются, так как при входе в эти каталоги фактически
выполняется выход (переход) в родительский каталог. Если этого не учесть, то
программа зациклится.
Листинг 12.3.
Программа поиск файлов
// поиск файла в указанном каталоге и его подкаталогах
// используется рекурсивная процедура Find
unit FindFile_;
interface
uses
Windows, Messages, SysUtils, Variants,
Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, FileCtr;
type
TForm1
= class(TForm)
Editl:
TEdit; // что искать
Edit2:
TEdit; // где искать
Memo1:
TMemo; // результат поиска
Button1:
TButton; // кнопка Поиск
Button2:
TButton; // кнопка Папка
Label1:
TLabel;
Label2:
TLabel;
Label3:
TLabel;
Label4:
TLabel;
procedure
Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
private
{
Private declarations }
public
{ Public declarations }
end;
var
Form1:
TForm1;
implementation
{$R
*.dfm}
var
FileName:
string; // имя или маска искомого файла
cDir:
string;
n:
integer; // кол-во файлов, удовлетворяющих запросу
//
поиск файла в текущем каталоге
procedure
Find;
var
SearchRec:
TSearchRec; // информация о файле или каталоге
begin
GetDir(0,cDir); // получить имя текущего каталога
if
cDir [length (cDir) ] <> 'V then cDir := cDir+'\';
if FindFirst(FileName, faArchive,SearchRec) = 0
then
repeat
if (SearchRec.Attr and faAnyFile) = SearchRec.Attr
then
begin
Form1.Memo1.Lines.Add(cDir + SearchRec.Name);
n
:= n + 1; end; until FindNext(SearchRec) <> 0;
// обработка подкаталогов текущего каталога
if
FindFirst('*', faDirectory, SearchRec) = 0 then repeat
if
(SearchRec.Attr and faDirectory) = SearchRec.Attr then begin
// каталоги .. и . тоже каталоги,
// но в них входить не надо .'.'.'
if
SearchRec.Name[1] <> '.' then begin
ChDir(SearchRec.Name);// войти в каталог
Find; // выполнить поиск в подкаталоге
ChDir('..');// выйти из каталога
end;
end;
until FindNext(SearchRec) <> 0;
end;
/ возвращает каталог, выбранный пользователем
function GetPath(mes: string):string;
var
Root: string; // корневой каталог
pwRoot : PWideChar; Dir: string;
begin
Root
:= '';
GetMem(pwRoot, (Length(Root)+1) * 2);
pwRoot := StringToWideChar(Root, pwRoot, MAX_PATH*2);
if
SelectDirectory(mes, pwRoot, Dir) then
if length(Dir) =2 // пользователь выбрал корневой каталог
then
GetPath := Dir+'\' else GetPath := Dir else
GetPath := '';
end;
щелчок
на кнопке Поиск
procedure TForml.ButtonlClick(Sender: TObject);
begin
Memo1.Clear;
// очистить поле Memol
Label4.Caption
:= '';
FileName
:= Edit1.Text; // что искать.
cDir
:= Edit2.Text; // где искать
n:=0;
// кол-во найденных файлов
ChDir(cDir);
// войти в каталог начала поиска
Find;
// начать поиск
if
n = 0 then
ShowMessage('Файлов, удовлетворяющих критерию поиска нет.')
else Label4.Caption := 'Найдено файлов:' + IntToStr(n);
end;
//
щелчок на кнопке Папка
procedure
TForml.Button2Click (Sender: TObject);
var
Path:
string; begin
Path
:= GetPath('Выберите папку');
if
Path <> ''
then Edit2.Text := Path;
end;
end.