Delphi-int.ru: портал программистов

Вход Регистрация | Забыли пароль?

Просмотр кода

Идентификатор: fbbcaf81 Описание: Код загружен: 27 апреля 2011, 14:51 (min@y™)

unit uSearchThread;
 
interface
 
uses
  Classes, SysUtils;
 
type
  // Поиск файлов соответствующих маске или кроме тех, которые соответствуют маске
  TFilterMethod = (fmIncludeMasks, fmExcludeMasks);
 
  // типы событий
  TFoundFileEvent = procedure (Sender: TObject;
                               const FileName: string;
                               const Size: Int64;
                               const DateTime: TDateTime) of object;
  TFolderChangeEvent = procedure (Sender: TObject;
                                  const NewPath: string) of object;
 
  // Класс-нить для поиска файлов по маскам в заданном каталоге
  TSearchThread = class(TThread)
  private
    // Поля
    FSearchPath: string; // путь поиска
    FMasks: TStrings; // список масок для поиска
    FFilterMethod: TFilterMethod; // способ фильтрации файлов
    FIncludeSubfolders: Boolean; // флаг поиска в подкаталогах
    FInProgress: Boolean; // флаг "в процессе"
    FCount: Cardinal; // кол-во найденных файлов
    FCurrentFolder: string; // каталог, в котором ведётся поиск в данный момент
    FCurrentFile: string; // очеденой найденный файл
    FCurrentFileSize: Int64; // размер найденного файла
    FCurrentFileTime: TDateTime; // время файла
    FOnFileFound: TFoundFileEvent; // событие при нахождении очередного файла
    FOnFolderChange: TFolderChangeEvent; // событие при вхождении в очередной каталог
 
    // Функции доступа к полям/свойствам
 
    // Технологические функции
    function MatchesMask(const S, Mask: string): Boolean; // Соответствие имени файла маске
    function MatchesMasks(const S: string): Boolean; // Соответствие имени файла одной из масок списка
    procedure FindFiles(const APath: string); // поиск файлов
  protected
    procedure Execute; override;
    procedure DoOnFileFound;
    procedure DoOnFolderChange;
  public
    constructor Create(const ASearchPath: string;
                       AMasks: TStrings;
                       const AFilterMethod: TFilterMethod;
                       const AIncludeSubfolters: Boolean = True); reintroduce;
 
    // Методы
    procedure Start;
    procedure Stop;
 
    // Свойства
    property Count: Cardinal read FCount;
    property CurrentFolder: string read FCurrentFolder;
    property InProgress: Boolean read FInProgress;
 
    // События
    property OnFileFound: TFoundFileEvent read FOnFileFound write FOnFileFound;
    property OnFolderChange: TFolderChangeEvent read FOnFolderChange write FOnFolderChange;
  end;
 
 
implementation
 
{ TSearchThread }
 
constructor TSearchThread.Create(const ASearchPath: string;
                                 AMasks: TStrings;
                                 const AFilterMethod: TFilterMethod;
                                 const AIncludeSubfolters: Boolean = True);
var
  Index: Integer;
begin
  inherited Create(True);
 
  FSearchPath:=        ASearchPath;
  FMasks:=             AMasks;
 
  for Index:= 0 to FMasks.Count - 1 do
    FMasks[Index]:= AnsiLowerCaseFileName(FMasks[Index]);
 
  FFilterMethod:=      AFilterMethod;
  FIncludeSubfolders:= AIncludeSubfolters;
end;
 
procedure TSearchThread.DoOnFileFound;
begin
  if Assigned(FOnFileFound)
    then FOnFileFound(Self, FCurrentFile, FCurrentFileSize, FCurrentFileTime);
end;
 
procedure TSearchThread.DoOnFolderChange;
begin
  if Assigned(FOnFolderChange)
    then FOnFolderChange(Self, FCurrentFolder);
end;
 
procedure TSearchThread.Execute;
begin
  FInProgress:= True;
  FindFiles(FSearchPath);
  FInProgress:= False;
end;
 
 
procedure TSearchThread.FindFiles(const APath: string);
var
  Rec: TSearchRec;
  Condition: Boolean;
  FindResult: Integer;
begin
  // Поиск в каталоге
 
  // вызов события
  FCurrentFolder:= APath;
  Synchronize(DoOnFolderChange);
 
  FindResult:= FindFirst(APath + '\*.*', faAnyFile, Rec);
  try
    if FindResult = 0
      then repeat
             if Terminated
               then Break; // Прерывание
 
             if (Rec.Name <> '.') and (Rec.Name <> '..')
               then begin
                      // Наткнулся на файл
                      if Rec.Attr and faDirectory = 0
                        then begin
                               if FFilterMethod = fmIncludeMasks
                                 then Condition:= MatchesMasks(AnsiLowerCase(Rec.Name))
                                 else Condition:= not MatchesMasks(AnsiLowerCase(Rec.Name));
 
                               if Condition
                                 then begin
                                        // вызов события
                                        Inc(FCount);
                                        FCurrentFile:= APath + '\' + Rec.Name;
                                        FCurrentFileSize:= Rec.Size;
                                        FCurrentFileTime:= FileDateToDateTime(Rec.Time);
                                        Synchronize(DoOnFileFound);
                                      end;
                             end
 
                        // Наткнулся на каталог
                        else if FIncludeSubfolders
                               then FindFiles(APath + '\' + Rec.Name);
                    end;
           until FindNext(Rec) <> 0;
  finally
    FindClose(Rec);
  end;
end;
 
function TSearchThread.MatchesMask(const S, Mask: string): Boolean;
var
  si, mi: Integer;
  b: Boolean;
begin
  // Соответствие имени файла маске
  if Mask = ''
    then begin
           Result:= True;
           Exit;
         end;
 
    si:= 1;
    mi:= 1;
 
    while mi <= Length(mask) do
      begin
        case mask[mi] of
          '?': begin
                 Inc(si);
                 Inc(mi);
                 Continue;
               end; // '?':
 
          '*': begin
                 if mi = Length(mask)
                   then begin
                          Result:= True;
                          Exit
                        end;
 
                 Inc(mi);
 
                 while si <= Length(s) + 1 do
                   begin
                     b := MatchesMask(Copy(s, si, Length(s) - si + 1),
                                      Copy(mask, mi, Length(mask) - mi + 1));
                     if b
                       then begin
                              Result:= True;
                              Exit
                            end;
 
                     Inc(si);
                   end; // while
 
                 Result:= False;
                 Exit;
               end; // '*':
          else begin
                 if si > Length(s)
                   then begin
                          Result:= False;
                          Exit
                        end;
 
                 if s[si] <> mask[mi]
                   then begin
                          Result:= False;
                          Exit;
                        end;
               end // else
        end; // case
 
        Inc(si);
        Inc(mi);
    end; // while
 
  Result:= (si = Length(s) + 1) and (mi = Length(mask) + 1);
end;
 
function TSearchThread.MatchesMasks(const S: string): Boolean;
var
  Index: Integer;
begin
  if FMasks.Count = 0  // если маски не заданы
    then begin
           Result:= True;
           Exit;
         end;
 
  for Index:= 0 to FMasks.Count - 1 do
    begin
      Result:= MatchesMask(S, FMasks[Index]);
 
      if Result
        then Exit;
    end;
 
  Result:= False;
end;
 
procedure TSearchThread.Start;
begin
  if not FInProgress
    then begin
           FCount:= 0;
           Resume();
         end;
end;
 
procedure TSearchThread.Stop;
begin
  Self.Terminate();
end;
 
end.

Ссылка на данный код:

На главную страницу сервиса обмена кодом »