Пошук файлів у Delphi, Delphi, компоненти Delphi, вихідні джерела Delphi

Пошук файлів у Delphi

Розглянемо наступний приклад:

hFindFile := FindFirst(Маска пошуку, Атрибути, Інформація);

//Перевіряємо коректність знайденого файлу

if hFindFile про INVALID_HANDLE_VALUE then

//Якщо коректно, то запускається цикл repeat - until, repeat

//Тут вписані оператори, які потрібно виконувати, until (FindNext (Інформація) про 0);

FindFirst - відкриває пошук. Як перший параметр виступає маска пошуку. Якщо ви вкажете конкретний файл, система знайде саме його. Ви також можете шукати цілі групи файлів. Наприклад, можна запустити пошук усіх файлів у кореневому каталозі диска С:. Для цього перший параметр повинен бути визначений як -'с: \ *. * '. Для пошуку тільки ЕХЕ-файлів, у папці Fold ви повинні вказати -'з: \Fold\ * . ехе'.

Другий параметр — атрибути, які використовуються під час пошуку файлів. Щоб шукати будь-які файли, потрібно вказати faAnyFiie. Крім цього, можна шукати за такими атрибутами:

  • faReadOnly – шукати файли з атрибутом Readonly (тільки для читання);
  • faHidden - шукати приховані файли;
  • faSysFile – шукати системні файли;
  • faArchive - шукати архівні файли;
  • faDirectory – шукати папки.

Останній параметр-це структура, в якій нам повернеться інформація про пошук, а саме: ім'я знайденого файлу, розмір, час створення і т.д.

Після дзвінка цієї процедури, ми повинні перевірити на коректність знайдений файл. Якщо результат дорівнюєinvalid_handle_value, то функція не знайшла жодного файлу. Якщо все нормально і файл, що відповідає критеріям пошуку, існує, то запускається циклRepeat.. .until.

Ми вже розглядали цикли, але все ж таки повторимося і згадаємо їхню роботу. Цикл виконуєоператори, розташовані між repeat та until, поки умова, розташована після слова until, виконується. Як тільки умова порушується, цикл переривається.

Тут слід помітити, що функція пошуку повертає через параметр Інформація імена файлів і може повернути нам як ім'я точку або дві точки. Якщо ви подивитеся на папку, таких файлів не буде. Звідки беруться ці імена? Назва файлу у вигляді точки вказує на поточну папку, а ім'я файлу з двох точок вказує на папку верхнього рівня. Якщо ми зустрічаємо такі імена, їх потрібно просто відкидати.

Параметр Інформація має тип структури TSearchRec. Давайте розглянемо її докладніше. Оголошення виглядає так:

TSearchRec = record Time: Integer; // Час створення знайденого файлу

Size: Integer; // Розмір знайденого файлу

Attr: Integer; // Атрибути знайденого файлу

Name: TFileName; // Ім'я знайденого файлу

ExcludeAttr: Integer; // Виключені атрибути знайденого файлу

FindHandle: THandle; // Покажчик, необхідний пошуку

F.inddata: TWin32FindData; // Структура пошуку файлу Winndows

Функція FindNext змушує знайти наступний файл, який відповідає параметрам, вказаним у функціїFindFirst. Цій функції потрібно передати структуру searchRec, за якою буде визначено, де зараз зупинено пошук, і з цього моменту він буде продовжено. Як тільки буде знайдено новий файл, функція поверне у структурі SearchRec інформацію про новий знайдений файл.

Функція Findciose закриває пошук. Як єдиний параметр потрібно вказати ту саму структуру SearchRec.

Давайте напишемо якийсь реальний приклад, який наочно покаже роботу з функціями пошуку файлів. Подивіться структуруTSearchRec. Як бачите,вона може повертати розмір знайденого файла. Ось і тема для прикладу – ми напишемо код, який визначатиме розмір вказаного файлу.

Створіть новий проект та встановіть на форму два компоненти TEdit та одну кнопку. Можете прикрасити все це текстом. У вас має вийти щось схоже на рис. 10.4.

Після натискання кнопки (подія onclick) напишіть наступний код:

SearchRec:TSearchRec; begin // Шукаємо файл

if FindFirst(Editl.Text, faAnyFile,SearchRec)=0 then

Edit2.Text:=IntToStr(SearchRec. Size)+ 'байт';

//Закриваємо пошук FindClose(SearchRec); end;

Ускладнимо приклад і спробуємо написати програму, яка шукатиме файл на диску, при цьому скануватиме і вкладені папки. Це завдання дуже зручно вирішувати через рекурсію. Коли ми розглядали цю тему, то реалізували абсолютно непотрібний приклад, який краще вирішувати через простий цикл. В даному випадку ви побачите реальну міць рекурсії, закріпите знання функцій пошуку та побачите непоганий алгоритм.

Отже, для прикладу нам знадобляться на формі два поля введення з іменами:

  • edLookFor - в ньому будуть вводити ім'я файлу, який потрібно знайти;
  • edLookin - диск або шлях до папки, де потрібно шукати, включаючи вкладені папки. Нам також знадобляться кнопка, після натискання якої відбуватиметься сканування, і поле введення Memo, куди буде виводитися результат, адже файл з одним і тим самим ім'ям може бути в кількох папках.

Після натискання кнопки пишемо наступний код:

procedure ScanFolder(Folder: String);

procedure TForm1.ScanFolder(Folder: String); var

sr: TSearchRec; FileName:String;

if FindFirst(Folder+'\*.*', faAnyFile, sr) = 0 then begin repeat

if (sr.Name= 1 . 1) or (sr.Name=' . . ') then continue;

FileName := SlashSep(Folder, sr.Name);

if (sr.Attr and faDirectory) = faDirectory then begin

i f AnsiUpperCase(edLookFor;Text)=AnsiUpperCase(sr.Name) then Memol.Lines.Add(FileName) ;

FindClose(sr); end; end;

У першому рядку запускаємо пошук за допомогою функції FindFirst. Як перший параметр передається папка плюс маска Vs.*'. Другий параметр дорівнює faAnyFile, щоб функція шукала для нас усі файли будь-якого типу. Останній параметр – це структура TSearchRec, через яку ми отримуватимемо результат. Якщо файл знайдено, то перевіряємо, якщо ім'я дорівнює точці або двом точкам, то продовжуємо пошук далі.

Після цього змінну FileName поміщаємо повний шлях знайденого файла. Для цього використовуємо функцію SlashSep. Ця функція не існує в Delphi, ми повинні самі її написати:

function SlashSep(Path, FName: string): string;

if Path[Length(Path)] <> '\' then Result := Path + '\'+ FName else Result := Path + FName;

Функція отримує як параметр шлях і ім'я файлу. Сенс у тому, що й шлях не закінчується слешем, його треба додати. Саме це тут і робиться.

Повернімося до лістингу 10.18. На наступній стадії триває перевірка, що саме ми знайшли – файл чи папку. Якщо це папка, потрібно пошукати файл всередині неї. Для цього ми викликаємо ScanFolder, вказуючи вкладену папку. Але ми вже знаходимося в цій функції, виходить, що функція буде викликати сама себе? Правильно це і є рекурсія. Ми знову викликаємо ScanFolder із зазначенням вкладеної папки, і цей виклик буде продовжуватися, доки всі папки не будуть проскановані.

Якщо ми не знайшли папку, то перевіряємо ім'я файлу. Якщо воно збігається з шуканим, то виводимо відповідне повідомлення Memo компонент. Отже, пошукпродовжується доти, доки не переберемо всі файли.

Цей приклад хороший, але ефективний. Справа в тому, що ми перебиратимемо абсолютно всі файли в кожній папці, що не ефективно. Набагато швидше шукатиме конкретний файл відразу. Для цього перший рядок змінюємо таким чином:

Ось тепер як перший параметр ми вказуємо не просто шлях з маскою, а конкретний файл, і результат буде позитивним тільки в тому випадку, коли в папці є потрібний файл.

Як рядок пошуку можна вказувати і маски, наприклад, наступний рядок шукає всі INI-файли в корені диска С:

Але коли ви вказуєте конкретний файл, функція не повертатиме папки. Як вирішити цю проблему? Спробуйте самі подумати. Є досить елегантне рішення.