Главная » Delphi » Поток поиска

0

Реализация механизма поиска  содержится в модуле SrchU.pas, который пред ставлен  в листинге 5.9. Этот  модуль выполняет массу интересных вещей, включая  ко пирование целого  файла  в строку,  рекурсивный проход каталогов и передачу  инфор мации в главную форму.

Листинг 5.9. Модуль SrchU.pas

unit SrchU;

interface

uses Classes, StdCtrls;

type

TSearchThread = class(TThread)

private

LB: TListbox;

CaseSens: Boolean;

FileNames: Boolean;

Recurse: Boolean;

SearchStr: string;

SearchPath: string;

FileSpec: string;

AddStr: string;

FSearchFile: string;

procedure AddToList;

procedure DoSearch(const Path: string);procedure FindAllFiles(const Path: string);

procedure FixControls;

procedure ScanForStr(const FName: string;

var FileStr: string);

procedure SearchFile(const FName: string);

procedure SetSearchFile;

protected

procedure Execute; override;

public

constructor Create(CaseS, FName, Rec: Boolean;

const Str, SPath, FSpec: string);

destructor Destroy; override;

end;

implementation

uses SysUtils, StrUtils, Windows, Forms, Main;

constructor TSearchThread.Create(CaseS, FName, Rec: Boolean;

const Str, SPath, FSpec: string);

begin

CaseSens := CaseS;

FileNames := FName;

Recurse := Rec;

SearchStr := Str;

SearchPath := AddBackSlash(SPath);

FileSpec := FSpec;

inherited Create(False);

end;

destructor TSearchThread.Destroy;

begin

FSearchFile := ”;

Synchronize(SetSearchFile);

Synchronize(FixControls);

inherited Destroy;

end;

procedure TSearchThread.Execute;

begin

FreeOnTerminate := True;         // освободить все поля

LB := MainForm.lbFiles;

Priority := TThreadPriority(MainForm.SearchPri);

if not CaseSens then SearchStr := UpperCase(SearchStr);

FindAllFiles(SearchPath);         // обработать текущий каталог

if Recurse then DoSearch(SearchPath); // Если каталог,

end;                                     // то рекурсия.

procedure TSearchThread.FixControls;

{ Разрешает работу элементов управления в основной форме. Следует

вызывать через Synchronize }

begin

MainForm.EnableSearchControls(True);end;

procedure TSearchThread.SetSearchFile;

{ Обновляет имя файла в строке состояния. Следует вызывать через

Synchronize }

begin

MainForm.StatusBar.Panels[1].Text := FSearchFile;

end;

procedure TSearchThread.AddToList;

{ Добавляет строку в основной список. Следует вызывать через Syn-

chronize }

begin

LB.Items.Add(AddStr);

end;

procedure TSearchThread.ScanForStr(const FName: string;

var FileStr: string);

{ Ищет подстроку SearchStr в строке FileStr файла FName. }

var

Marker: string[1];

FoundOnce: Boolean;

FindPos: integer;

begin

FindPos := Pos(SearchStr, FileStr);

FoundOnce:= False;

while (FindPos <> 0) and not Terminated do begin

if not FoundOnce then begin

// Использовать ":", если пользователь не выбрал

// флажок "File Names Only" (Только имена файлов).

if FileNames then Marker := ”

else Marker := ‘:';

{ Добавить файл в список }

AddStr := Format(‘File %s%s’, [FName, Marker]);

Synchronize(AddToList);

FoundOnce := True;

end;

// Если нужны только имена, то не искать ту же самую строку в

// том же самом файле }

if FileNames then Exit;

{ Если нужны только имена, то добавить строку }

AddStr := GetCurLine(FileStr, FindPos);

Synchronize(AddToList);

FileStr := Copy(FileStr, FindPos + Length(SearchStr),

Length(FileStr));

FindPos := Pos(SearchStr, FileStr);

end;

end;

procedure TSearchThread.SearchFile(const FName: string);

{ Ищет строку SearchStr в файле FName. }

var

DataFile: THandle;FileSize: Integer; SearchString: string;

begin

FSearchFile := FName;

Synchronize(SetSearchFile);

try

DataFile := FileOpen(FName, fmOpenRead or fmShareDenyWrite);

if DataFile = 0 then raise Exception.Create(”);

try

{ установить длину искомой строки }

FileSize := GetFileSize(DataFile, nil);

SetLength(SearchString, FileSize);

{ копировать содержимое файла в строку }

FileRead(DataFile, Pointer(SearchString)^, FileSize);

finally

CloseHandle(DataFile);

end;

if not CaseSens then SearchString := UpperCase(SearchString);

ScanForStr(FName, SearchString);

except

on Exception do begin

AddStr := Format(‘Error reading file: %s’, [FName]);

Synchronize(AddToList);

end;

end;

end;

procedure TSearchThread.FindAllFiles(const Path: string);

{ Ищет в подкаталогах пути файлы, отвечающие спецификации }

var

SR: TSearchRec;

begin

{ Поиск первого файла, соответствующего спецификации }

if FindFirst(Path + FileSpec, faArchive, SR) = 0 then

try

repeat

SearchFile(Path + SR.Name);

//

обработка файла

until (FindNext(SR) <> 0) or Terminated;

//

найти след. файл

finally

SysUtils.FindClose(SR);                       // освободить память

end;

end;

procedure TSearchThread.DoSearch(const Path: string);

{ Рекурсивно обрабатывает дерево подкаталогов, начиная с пути Path.

}

var

SR: TSearchRec;

begin

{ Просмотр каталогов }

if FindFirst(Path + ‘*.*’, faDirectory, SR) = 0 then

try

repeat{ Если это каталог и нет ‘.’ или ‘..’ то… }

if ((SR.Attr and faDirectory) <> 0) and (SR.Name[1] <> ‘.’)

FindAllFiles(Path + SR.Name + ‘\’);

//

обработка каталога

DoSearch(Path + SR.Name + ‘\’);

//

рекурсия

end;

until (FindNext(SR) <> 0) or Terminated;

//

Найти следующий

inally

//

каталог.

SysUtils.FindClose(SR);

//

освободить память

 

and not Terminated then begin

f

end;

end;

end.При  создании этого  потока сначала  вызывается метод FindAllFiles(), который использует функции FindFirst() и FindNext() для поиска  в текущем каталоге всех файлов, соответствующих маске,  заданной пользователем. Если пользователь устано вил флажок Recurse subdirs (Включая вложенные папки), то для исследования дерева подкаталогов вызывается метод  DoSearch(). Данный метод  пользуется услугами ме тодов FindFirst() и FindNext(), но на этот раз — для обнаружения каталогов, при чем весь фокус заключается в том,  что  для операций внутри  дерева  подкаталогов ме тод DoSearch() выполняет рекурсию, т.е. вызывает сам себя. При  обнаружении каж дого каталога вызывается процедура FindAllFiles(), которая обрабатывает все файлы, отвечающие условиям поиска.

CОВЕТ

Алгоритм рекурсии, используемый процедурой DoSearch(), является стандартным методом прохода дерева каталогов. Как известно, рекурсивные алгоритмы представ- ляют определенную трудность для отладки, поэтому опытные программисты старают- ся использовать проверенные, заведомо работающие алгоритмы. Учитывая вышеска- занное, рекомендуем сохранять этот метод, чтобы впоследствии можно было приме- нить его в других приложениях.

Обратите внимание: при  поиске заданной лексемы  внутри  файла  используется объ ект TMemMapFile, который в системе Win32 инкапсулирует файл,  отображенный в па мять. Более  подробная информация об этом объекте приведена в предыдущем издании, в главе 12 — “Работа  с файлами”, но вполне достаточно знать,  что он предоставляет со бой простой способ  отображения содержимого любого  файла  в память.  Полный алго ритм работает следующим образом.

1.  При   обнаружении  методом FindAllFiles() файла,  отвечающего заданной спецификации, вызывается метод SearchFile() и его содержимое копируется в строку.

2.   Для  каждого  файла строки вызывается  метод  ScanForStr(),  который  осуще

ствляет в строке поиск вхождения искомой подстроки.

3.  Если вхождение подстроки обнаружено, то в список, отображаемый на форме, добавляется имя файла  и/или строка текста.  Строка текста  добавляется тольков  том  случае,   если   пользователь  не  устанавливал  флажок  File  Names  Only

(Только имена файлов).

Обратите внимание, все методы  объекта TSearchThread периодически проверяют состояние флагов  StopIt (который устанавливается при  остановке потока) и Termi- nated (который устанавливается при завершении работы с объектом TThread).

CОВЕТ

Помните, что все методы объекта TThread, которые используют пользовательский ин- терфейс приложения, должны вызываться с помощью метода Synchronize(). Аль- тернативный способ модификации пользовательского интерфейса заключается в по- сылке сообщений.

Источник: Тейксейра, Стив, Пачеко, Ксавье.   Borland Delphi 6. Руководство разработчика. : Пер.  с англ. — М. : Издательский дом “Вильямс”, 2002. —  1120 с. : ил. — Парал. тит. англ.

По теме:

  • Комментарии