Пошук файлів

Як приклад використання рекурсії розглянемо задачу пошуку файлів. Нехай потрібно отримати список всіх файлів, наприклад, з розширенням 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.