unit SearchDir;

interface

uses
  Classes, SysUtils;

type
  TFindFileFunction = procedure (Sender:TObject; APath:string; AFileInfo:TSearchRec);
  TFindFolderFunction = procedure (Sender:TObject; AFolder:string);

  TFindFileEvent = procedure (Sender:TObject; APath:string; AFileInfo:TSearchRec) of object;
  TFindFolderEvent = procedure (Sender:TObject; AFolder:string) of object;

  TSearchDir = class (TComponent)
  private
    FStoped : boolean;
    procedure SearchDirectory(APath,AFileName:string);
  private
    FSearchSubDirectories: boolean;
    FOnFindFolder: TFindFolderEvent;
    FOnFindFile: TFindFileEvent;
  public
    Sender : TObject;
    FindFileFunction : TFindFileFunction;
    FindFolderFunction : TFindFolderFunction;

    constructor Create(AOwner: TComponent); override;

    procedure Search(APath,AFileName:string); overLoad;
    procedure Search(APath:string); overload;

    procedure Stop;
  published
    property SearchSubDirectories : boolean read FSearchSubDirectories write FSearchSubDirectories;
    property OnFindFile : TFindFileEvent read FOnFindFile write FOnFindFile;
    property OnFindFolder : TFindFolderEvent read FOnFindFolder write FOnFindFolder;
  end;

implementation

{ TSearchDir }

constructor TSearchDir.Create(AOwner: TComponent);
begin
  inherited;

  FSearchSubDirectories := true;
end;

procedure TSearchDir.Search(APath, AFileName: string);
begin
  FStoped := false;
  if Copy(APath, Length(APath), 1) <> '\' then APath := APath + '\';

  SearchDirectory(APath, AFileName);
end;

procedure TSearchDir.Search(APath: string);
begin
  Search(APath, '*.*');
end;

procedure TSearchDir.SearchDirectory(APath, AFileName: string);
var
  SearchRec : TSearchRec;
  SearchResult : Integer;
begin
  if Assigned(FOnFindFolder) then FOnFindFolder(Self, APath);
  if Assigned(FindFolderFunction) then FindFolderFunction(Sender, APath);

  SearchResult := FindFirst(APath + AFileName, faAnyFile, SearchRec);
  while SearchResult = 0 do begin
    if FStoped then Break;

    // 디랙토리 중 무시해야할 것들
    if (SearchRec.Name = '.' ) or (SearchRec.Name = '..') then begin
      SearchResult := FindNext(SearchRec);
      Continue;
    end;

    // 하부디랙토리 검색 허용의 경우 처리
    if SearchSubDirectories and ((SearchRec.Attr and faDirectory) = faDirectory) then
      SearchDirectory(APath + SearchRec.Name + '\', AFileName);

    // 디렉토리일 경우에는 무시
    if ((SearchRec.Attr and faDirectory) <> faDirectory) then begin
      if Assigned(FOnFindFile) then FOnFindFile(Self, APath, SearchRec);
      if Assigned(FindFileFunction) then FindFileFunction(Sender, APath, SearchRec);
    end;

    SearchResult:= FindNext(SearchRec);
  end;

  FindClose(SearchRec);
end;

procedure TSearchDir.Stop;
begin
  FStoped := true;
end;

end.
