home *** CD-ROM | disk | FTP | other *** search
- {------------------------------------------------------------------------------}
- { }
- { TFindFile v3.02 }
- { by Kambiz R. Khojasteh }
- { }
- { kambiz@delphiarea.com }
- { http://www.delphiarea.com }
- { }
- { Special thanks to: }
- { Frederik Decoster <essevee@yahoo.com> for fixing folder look up bug. }
- { }
- {------------------------------------------------------------------------------}
-
- unit FindFile;
-
- interface
-
- uses
- Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
- Masks;
-
- type
-
- EFindFileError = class(Exception);
-
- TFileMatchEvent = procedure (Sender: TObject; const Folder: String;
- const FileInfo: TSearchRec) of object;
-
- TFolderChangeEvent = procedure (Sender: TObject; const Folder: String;
- var IgnoreFolder: Boolean) of object;
-
- TFileCriteria = class(TPersistent)
- private
- fFilename: String;
- fLocation: String;
- fIncluded: TStringList;
- fExcluded: TStringList;
- fSubfolders: Boolean;
- procedure SetIncluded(Value: TStringList);
- procedure SetExcluded(Value: TStringList);
- public
- constructor Create;
- destructor Destroy; override;
- procedure Assign(Source: TPersistent); override;
- published
- property FileName: String read fFilename write fFilename;
- property Location: String read fLocation write fLocation;
- property Included: TStringList read fIncluded write SetIncluded;
- property Excluded: TStringList read fExcluded write SetExcluded;
- property Subfolders: Boolean read fSubfolders write fSubfolders default True;
- end;
-
- TFileAttributes = set of (ffArchive, ffReadonly, ffHidden, ffSystem, ffDirectory);
-
- TAttributeCriteria = class(TPersistent)
- private
- fFlags: Integer;
- fExactMatch: Boolean;
- function GetAttributes: TFileAttributes;
- procedure SetAttributes(Value: TFileAttributes);
- public
- constructor Create;
- procedure Assign(Source: TPersistent); override;
- property Flags: Integer read fFlags write fFlags;
- function Matches(Attr: Integer): Boolean;
- published
- property Attributes: TFileAttributes read GetAttributes write SetAttributes
- default [ffArchive, ffReadonly, ffHidden, ffSystem];
- property ExactMatch: Boolean read fExactMatch write fExactMatch default False;
- end;
-
- TDateTimeCriteria = class(TPersistent)
- private
- fCreatedBefore: TDateTime;
- fCreatedAfter: TDateTime;
- fModifiedBefore: TDateTime;
- fModifiedAfter: TDateTime;
- fAccessedBefore: TDateTime;
- fAccessedAfter: TDateTime;
- public
- procedure Assign(Source: TPersistent); override;
- function Matches(const Created, Modified, Accessed: TFileTime): Boolean;
- published
- property CreatedBefore: TDateTime read fCreatedBefore write fCreatedBefore;
- property CreatedAfter: TDateTime read fCreatedAfter write fCreatedAfter;
- property ModifiedBefore: TDateTime read fModifiedBefore write fModifiedBefore;
- property ModifiedAfter: TDateTime read fModifiedAfter write fModifiedAfter;
- property AccessedBefore: TDateTime read fAccessedBefore write fAccessedBefore;
- property AccessedAfter: TDateTime read fAccessedAfter write fAccessedAfter;
- end;
-
- TSizeCriteria = class(TPersistent)
- private
- fMin: DWORD;
- fMax: DWORD;
- public
- procedure Assign(Source: TPersistent); override;
- function Matches(Size: DWORD): Boolean;
- published
- property Min: DWORD read fMin write fMin default 0;
- property Max: DWORD read fMax write fMax default 0;
- end;
-
- TContentCriteria = class(TPersistent)
- private
- fPhrase: String;
- fPhraseLen: Integer;
- fIgnoreCase: Boolean;
- fTargetPhrase: String;
- procedure SetPhrase(const Value: String);
- procedure SetIgnoreCase(Value: Boolean);
- protected
- property TargetPhrase: String read fTargetPhrase;
- public
- constructor Create;
- procedure Assign(Source: TPersistent); override;
- property PhraseLen: Integer read fPhraseLen;
- function Matches(const FileName: String): Boolean;
- published
- property Phrase: String read fPhrase write SetPhrase;
- property IgnoreCase: Boolean read fIgnoreCase write SetIgnoreCase default True;
- end;
-
- TSearchCriteria = class(TPersistent)
- private
- fFiles: TFileCriteria;
- fAttribute: TAttributeCriteria;
- fTimeStamp: TDateTimeCriteria;
- fSize: TSizeCriteria;
- fContent: TContentCriteria;
- procedure SetFiles(Value: TFileCriteria);
- procedure SetAttribute(Value: TAttributeCriteria);
- procedure SetTimeStamp(Value: TDateTimeCriteria);
- procedure SetSize(Value: TSizeCriteria);
- procedure SetContent(Value: TContentCriteria);
- public
- constructor Create;
- destructor Destroy; override;
- procedure Assign(Source: TPersistent); override;
- published
- property Files: TFileCriteria read fFiles write SetFiles;
- property Attribute: TAttributeCriteria read fAttribute write SetAttribute;
- property TimeStamp: TDateTimeCriteria read fTimeStamp write SetTimeStamp;
- property Size: TSizeCriteria read fSize write SetSize;
- property Content: TContentCriteria read fContent write SetContent;
- end;
-
- TTargetFolder = class(TObject)
- private
- fFolder: String;
- fSubfolders: Boolean;
- fFileMasks: TStringList;
- public
- constructor Create;
- destructor Destroy; override;
- property Folder: String read fFolder write fFolder;
- property Subfolders: Boolean read fSubfolders write fSubfolders;
- property FileMasks: TStringList read fFileMasks;
- end;
-
- TTargetFolderList = class(TList)
- private
- fExcludedFiles: TStringList;
- function GetItems(Index: Integer): TTargetFolder;
- public
- constructor Create;
- destructor Destroy; override;
- function IndexOfFolder(const Folder: String): Integer;
- function AddFolder(const Folder: String): TTargetFolder;
- function IsExcluded(const Folder, FileName: String): Boolean;
- property Items[Index: Integer]: TTargetFolder read GetItems; default;
- property ExcludedFiles: TStringList read fExcludedFiles;
- end;
-
- // TTargetSearch holds all running search parameters. This ables us to change
- // the component's properties without affecting the running search.
- TTargetSearch = class(TObject)
- protected
- TargetFolders: TTargetFolderList;
- Attribute: TAttributeCriteria;
- TimeStamp: TDateTimeCriteria;
- Size: TSizeCriteria;
- Content: TContentCriteria;
- procedure PrepareTargetFolders(FileCriteria: TFileCriteria);
- public
- constructor Create(Criteria: TSearchCriteria);
- destructor Destroy; override;
- function Matches(const Folder: String; const SR: TSearchRec): Boolean;
- end;
-
- TFindFile = class(TComponent)
- private
- fCriteria: TSearchCriteria;
- fThreaded: Boolean;
- fThreadPriority: TThreadPriority;
- fAborted: Boolean;
- fBusy: Boolean;
- fOnFileMatch: TFileMatchEvent;
- fOnFolderChange: TFolderChangeEvent;
- fOnSearchBegin: TNotifyEvent;
- fOnSearchFinish: TNotifyEvent;
- fOnSearchAbort: TNotifyEvent;
- SearchThread: TThread;
- TargetSearch: TTargetSearch;
- ActiveTargetFolder: TTargetFolder;
- procedure SetCriteria(Value: TSearchCriteria);
- procedure ThreadTerminated(Sender: TObject);
- protected
- procedure DoSearchBegin; virtual;
- procedure DoSearchFinish; virtual;
- procedure DoSearchAbort; virtual;
- function DoFolderChange(const Folder: String): Boolean; virtual;
- procedure DoFileMatch(const Folder: String; const FileInfo: TSearchRec); virtual;
- function IsAcceptable(const Folder: String; const SR: TSearchRec): Boolean;
- procedure InitializeSearch;
- procedure FinalizeSearch;
- procedure SearchForFiles;
- public
- constructor Create(AOwner: TComponent); override;
- destructor Destroy; override;
- procedure Execute;
- procedure Abort;
- property Busy: Boolean read fBusy;
- property Aborted: Boolean read fAborted;
- published
- property Criteria: TSearchCriteria read fCriteria write SetCriteria;
- property Threaded: Boolean read fThreaded write fThreaded default False;
- property ThreadPriority: TThreadPriority
- read fThreadPriority write fThreadPriority default tpNormal;
- property OnFileMatch: TFileMatchEvent read fOnFileMatch write fOnFileMatch;
- property OnFolderChange: TFolderChangeEvent read fOnFolderChange write fOnFolderChange;
- property OnSearchBegin: TNotifyEvent read fOnSearchBegin write fOnSearchBegin;
- property OnSearchFinish: TNotifyEvent read fOnSearchFinish write fOnSearchFinish;
- property OnSearchAbort: TNotifyEvent read fOnSearchAbort write fOnSearchAbort;
- end;
-
- procedure Register;
-
- function AddTrailingBackslash(const Path: String): String;
- function RemoveTrailingBackslash(const Path: String): String;
- function FileTimeToDateTime(const FileTime: TFileTime): TDateTime;
- function IsDateBetween(const aDate, Before, After: TDateTime): Boolean;
- function FileContains(const FileName: String; const Phrase: String;
- IgnoreCase: Boolean): Boolean;
-
- implementation
-
- uses
- FileCtrl;
-
- const
- Delimiter = ';';
- IncSubfolders = '>';
- ExcSubfolders = '<';
- ValidFileAttr = faAnyFile and not faVolumeID;
-
- procedure Register;
- begin
- RegisterComponents('Delphi Area', [TFindFile]);
- end;
-
- { Helper Functions }
-
- function AddTrailingBackslash(const Path: String): String;
- var
- PathLen: Integer;
- begin
- PathLen := Length(Path);
- if (PathLen > 0) and not (Path[PathLen] in ['\', ':']) then
- Result := Path + '\'
- else
- Result := Path;
- end;
-
- function RemoveTrailingBackslash(const Path: String): String;
- var
- PathLen: Integer;
- begin
- PathLen := Length(Path);
- if (PathLen > 1) and (Path[PathLen] = '\') and (Path[PathLen-1] <> ':') then
- Result := Copy(Path, 1, PathLen - 1)
- else
- Result := Path;
- end;
-
- function FileTimeToDateTime(const FileTime: TFileTime): TDateTime;
- var
- LocalFileTime: TFileTime;
- SystemTime: TSystemTime;
- begin
- FileTimeToLocalFileTime(FileTime, LocalFileTime);
- FileTimeToSystemTime(LocalFileTime, SystemTime);
- Result := SystemTimeToDateTime(SystemTime);
- end;
-
- function IsDateBetween(const aDate, Before, After: TDateTime): Boolean;
- begin
- Result := True;
- if Before <> 0 then
- if Frac(Before) = 0 then { Checks date only }
- Result := Result and (Int(aDate) <= Before)
- else if Int(Before) = 0 then { Checks time only }
- Result := Result and (Frac(aDate) <= Before)
- else { Checks date and time }
- Result := Result and (aDate <= Before);
- if After <> 0 then
- if Frac(After) = 0 then { Checks date only }
- Result := Result and (Int(aDate) >= After)
- else if Int(After) = 0 then { Checks time only }
- Result := Result and (Frac(aDate) >= After)
- else { Checks date and time }
- Result := Result and (aDate >= After);
- end;
-
- function FileContainsPhrase(const FileName: String; const Phrase: PChar;
- PhraseLen: Integer; MatchLowerCase: Boolean): Boolean;
- const
- MaxBufferSize = $F000; // Must be larger than PhraseLen
- var
- Stream: TFileStream;
- DataSize: Integer;
- BufferSize: Integer;
- Buffer, B, P: PChar;
- N, Offset: Integer;
- begin
- Result := False;
- Stream := TFileStream.Create(FileName, fmOpenRead or fmShareDenyNone);
- try
- DataSize := Stream.Size;
- if DataSize >= PhraseLen then
- begin
- if DataSize > MaxBufferSize then
- if PhraseLen <= MaxBufferSize then
- BufferSize := MaxBufferSize
- else
- BufferSize := PhraseLen
- else
- BufferSize := DataSize;
- GetMem(Buffer, BufferSize);
- try
- P := Phrase;
- Offset := 0;
- while (DataSize + Offset) >= PhraseLen do
- begin
- B := Buffer + Offset;
- N := BufferSize - Offset;
- if N > DataSize then N := DataSize;
- Stream.Read(B^, N);
- if MatchLowerCase then AnsiLowerBuff(B, N);
- Dec(DataSize, N);
- repeat
- if B^ = P^ then
- begin
- Inc(P);
- Inc(Offset);
- Result := (Offset = PhraseLen);
- end
- else if P <> Phrase then
- begin
- P := Phrase;
- Dec(B, Offset);
- Inc(N, Offset);
- Offset := 0;
- end;
- Inc(B);
- Dec(N);
- until Result or (N = 0);
- end;
- finally
- FreeMem(Buffer, BufferSize);
- end;
- end;
- finally
- Stream.Free;
- end;
- end;
-
- function FileContains(const FileName: String; const Phrase: String;
- IgnoreCase: Boolean): Boolean;
- begin
- if IgnoreCase then
- Result := FileContainsPhrase(FileName, PChar(LowerCase(Phrase)),
- Length(Phrase), True)
- else
- Result := FileContainsPhrase(FileName, PChar(Phrase),
- Length(Phrase), False);
- end;
-
- function StrMatches(const Str, Mask: String): Boolean;
- var
- SIdx, SLen: Integer;
- MIdx, MLen: Integer;
- M: Char;
- begin
- SLen := Length(Str); SIdx := 1;
- MLen := Length(Mask); MIdx := 1;
- while (SIdx <= SLen) and (MIdx <= MLen) do
- begin
- M := Mask[MIdx];
- case M of
- '*': SIdx := SLen;
- '?': ;
- else
- if UpCase(M) <> UpCase(Str[MIdx]) then
- Break;
- end;
- Inc(SIdx);
- Inc(MIdx);
- end;
- Result := (SIdx > SLen);
- end;
-
- function FileMatches(const FileDir, FileName, Mask: String): Boolean;
- var
- MaskDrive, MaskDir, MaskName: String;
- FileDrive, InnerFileDir: String;
- begin
- Result := False;
- MaskDir := ExtractFilePath(Mask);
- // Checkes file path part, if mask contains path
- if Length(MaskDir) > 0 then
- begin
- FileDrive := ExtractFileDrive(FileDir);
- MaskDrive := ExtractFileDrive(MaskDir);
- // Checkes drive, if mask contains drive
- if Length(MaskDrive) > 0 then
- begin
- if not StrMatches(FileDrive, MaskDrive) then
- Exit; // Not Matched, drives are different
- // Removes drive part from the Mask
- Delete(MaskDir, 1, Length(MaskDrive));
- end;
- // Checkes directory
- if Length(MaskDir) > Length(FileDir) - Length(FileDrive) then
- Exit // Not Matched, Mask's length is longer than folder's length
- else
- begin
- // Checkes most inner directories
- InnerFileDir := Copy(FileDir, Length(FileDir) - Length(MaskDir) + 1, Length(MaskDir));
- if CompareText(InnerFileDir, MaskDir) <> 0 then
- Exit; // Not Matched
- end;
- end;
- // Checkes file name part if mask contains filename
- MaskName := ExtractFileName(Mask);
- if Length(MaskName) > 0 then
- Result := MatchesMask(FileName, MaskName)
- else
- Result := True; // Matched
- end;
-
- { TFileCriteria }
-
- constructor TFileCriteria.Create;
- begin
- inherited Create;
- fIncluded := TStringList.Create;
- fExcluded := TStringList.Create;
- fSubfolders := True;
- end;
-
- destructor TFileCriteria.Destroy;
- begin
- fIncluded.Free;
- fExcluded.Free;
- inherited Destroy;
- end;
-
- procedure TFileCriteria.Assign(Source: TPersistent);
- begin
- if Source is TFileCriteria then
- begin
- Filename := TFileCriteria(Source).FileName;
- Location := TFileCriteria(Source).Location;
- Included := TFileCriteria(Source).Included;
- Excluded := TFileCriteria(Source).Excluded;
- Subfolders := TFileCriteria(Source).Subfolders;
- end
- else
- inherited Assign(Source);
- end;
-
- procedure TFileCriteria.SetIncluded(Value: TStringList);
- begin
- fIncluded.Assign(Value);
- end;
-
- procedure TFileCriteria.SetExcluded(Value: TStringList);
- begin
- fExcluded.Assign(Value);
- end;
-
- { TAttributeCriteria }
-
- constructor TAttributeCriteria.Create;
- begin
- inherited Create;
- fFlags := faArchive or faReadonly or faHidden or faSysFile;
- fExactMatch := False;
- end;
-
- procedure TAttributeCriteria.Assign(Source: TPersistent);
- begin
- if Source is TAttributeCriteria then
- begin
- Flags := TAttributeCriteria(Source).Flags;
- ExactMatch := TAttributeCriteria(Source).ExactMatch;
- end
- else
- inherited Assign(Source);
- end;
-
- function TAttributeCriteria.GetAttributes: TFileAttributes;
- begin
- Result := [];
- if (Flags and faArchive) = faArchive then
- Include(Result, ffArchive);
- if (Flags and faReadonly) = faReadonly then
- Include(Result, ffReadonly);
- if (Flags and faHidden) = faHidden then
- Include(Result, ffHidden);
- if (Flags and faSysFile) = faSysFile then
- Include(Result, ffSystem);
- if (Flags and faDirectory) = faDirectory then
- Include(Result, ffDirectory);
- end;
-
- procedure TAttributeCriteria.SetAttributes(Value: TFileAttributes);
- var
- NewFlags: Integer;
- begin
- NewFlags := 0;
- if ffArchive in Value then
- NewFlags := NewFlags or faArchive;
- if ffReadonly in Value then
- NewFlags := NewFlags or faReadonly;
- if ffHidden in Value then
- NewFlags := NewFlags or faHidden;
- if ffSystem in Value then
- NewFlags := NewFlags or faSysFile;
- if ffDirectory in Value then
- NewFlags := NewFlags or faDirectory;
- Flags := NewFlags;
- end;
-
- function TAttributeCriteria.Matches(Attr: Integer): Boolean;
- begin
- Attr := Attr and ValidFileAttr;
- Result := (not ExactMatch or (Flags = Attr)) and
- (ExactMatch or ((not Flags and Attr) = 0));
- end;
-
- { TDateTimeCriteria }
-
- procedure TDateTimeCriteria.Assign(Source: TPersistent);
- begin
- if Source is TDateTimeCriteria then
- begin
- CreatedBefore := TDateTimeCriteria(Source).CreatedBefore;
- CreatedAfter := TDateTimeCriteria(Source).CreatedAfter;
- ModifiedBefore := TDateTimeCriteria(Source).ModifiedBefore;
- ModifiedAfter := TDateTimeCriteria(Source).ModifiedAfter;
- AccessedBefore := TDateTimeCriteria(Source).AccessedBefore;
- AccessedAfter := TDateTimeCriteria(Source).AccessedAfter;
- end
- else
- inherited Assign(Source);
- end;
-
- function TDateTimeCriteria.Matches(const Created, Modified, Accessed: TFileTime): Boolean;
- var
- DateTime: TDateTime;
- begin
- Result := False;
- if (CreatedBefore <> 0) or (CreatedAfter <> 0) then
- begin
- DateTime := FileTimeToDateTime(Created);
- if not IsDateBetween(DateTime, CreatedBefore, CreatedAfter) then Exit;
- end;
- if (ModifiedBefore <> 0) or (ModifiedAfter <> 0) then
- begin
- DateTime := FileTimeToDateTime(Modified);
- if not IsDateBetween(DateTime, ModifiedBefore, ModifiedAfter) then Exit;
- end;
- if (AccessedBefore <> 0) or (AccessedAfter <> 0) then
- begin
- DateTime := FileTimeToDateTime(Accessed);
- if not IsDateBetween(DateTime, AccessedBefore, AccessedAfter) then Exit;
- end;
- Result := True;
- end;
-
- { TSizeCriteria }
-
- procedure TSizeCriteria.Assign(Source: TPersistent);
- begin
- if Source is TSizeCriteria then
- begin
- Min := TSizeCriteria(Source).Min;
- Max := TSizeCriteria(Source).Max;
- end
- else
- inherited Assign(Source);
- end;
-
- function TSizeCriteria.Matches(Size: DWORD): Boolean;
- begin
- Result := ((Min = 0) or (Size >= Min)) and ((Max = 0) or (Size <= Max));
- end;
-
- { TContentCriteria }
-
- constructor TContentCriteria.Create;
- begin
- inherited Create;
- fIgnoreCase := True;
- end;
-
- procedure TContentCriteria.Assign(Source: TPersistent);
- begin
- if Source is TContentCriteria then
- begin
- Phrase := TContentCriteria(Source).Phrase;
- IgnoreCase := TContentCriteria(Source).IgnoreCase;
- end
- else
- inherited Assign(Source);
- end;
-
- procedure TContentCriteria.SetPhrase(const Value: String);
- begin
- if Phrase <> Value then
- begin
- fPhrase := Value;
- fPhraseLen := Length(Value);
- if IgnoreCase then
- fTargetPhrase := LowerCase(Phrase)
- else
- fTargetPhrase := Phrase;
- end;
- end;
-
- procedure TContentCriteria.SetIgnoreCase(Value: Boolean);
- begin
- if IgnoreCase <> Value then
- begin
- fIgnoreCase := Value;
- if IgnoreCase then
- fTargetPhrase := LowerCase(Phrase)
- else
- fTargetPhrase := Phrase;
- end;
- end;
-
- function TContentCriteria.Matches(const FileName: String): Boolean;
- begin
- if PhraseLen > 0 then
- try
- Result := FileContainsPhrase(FileName, PChar(TargetPhrase), PhraseLen, IgnoreCase)
- except
- Result := False;
- end
- else
- Result := True;
- end;
-
- { TSearchCriteria }
-
- constructor TSearchCriteria.Create;
- begin
- inherited Create;
- fFiles := TFileCriteria.Create;
- fAttribute := TAttributeCriteria.Create;
- fTimeStamp := TDateTimeCriteria.Create;
- fSize := TSizeCriteria.Create;
- fContent := TContentCriteria.Create;
- end;
-
- destructor TSearchCriteria.Destroy;
- begin
- fFiles.Free;
- fAttribute.Free;
- fTimeStamp.Free;
- fSize.Free;
- fContent.Free;
- inherited Destroy;
- end;
-
- procedure TSearchCriteria.Assign(Source: TPersistent);
- begin
- if Source is TSearchCriteria then
- begin
- Files := TSearchCriteria(Source).Files;
- Attribute := TSearchCriteria(Source).Attribute;
- TimeStamp := TSearchCriteria(Source).TimeStamp;
- Size := TSearchCriteria(Source).Size;
- Content := TSearchCriteria(Source).Content;
- end
- else
- inherited Assign(Source);
- end;
-
- procedure TSearchCriteria.SetFiles(Value: TFileCriteria);
- begin
- Files.Assign(Value);
- end;
-
- procedure TSearchCriteria.SetAttribute(Value: TAttributeCriteria);
- begin
- Attribute.Assign(Value);
- end;
-
- procedure TSearchCriteria.SetTimeStamp(Value: TDateTimeCriteria);
- begin
- TimeStamp.Assign(Value);
- end;
-
- procedure TSearchCriteria.SetSize(Value: TSizeCriteria);
- begin
- Size.Assign(Value);
- end;
-
- procedure TSearchCriteria.SetContent(Value: TContentCriteria);
- begin
- Content.Assign(Value);
- end;
-
- { TTargetFolder }
-
- constructor TTargetFolder.Create;
- begin
- inherited Create;
- fFileMasks := TStringList.Create;
- end;
-
- destructor TTargetFolder.Destroy;
- begin
- fFileMasks.Free;
- inherited Destroy;
- end;
-
- { TTargetFolderList }
-
- constructor TTargetFolderList.Create;
- begin
- inherited Create;
- fExcludedFiles := TStringList.Create;
- end;
-
- destructor TTargetFolderList.Destroy;
- var
- Index: Integer;
- begin
- fExcludedFiles.Free;
- for Index := Count - 1 downto 0 do
- Items[Index].Free;
- inherited Destroy;
- end;
-
- function TTargetFolderList.IndexOfFolder(const Folder: String): Integer;
- var
- Index: Integer;
- begin
- Result := -1;
- for Index := 0 to Count - 1 do
- if CompareText(Folder, Items[Index].Folder) = 0 then
- begin
- Result := -1;
- Break;
- end;
- end;
-
- function TTargetFolderList.AddFolder(const Folder: String): TTargetFolder;
- var
- Index: Integer;
- FullPath: String;
- begin
- FullPath := AddTrailingBackslash(ExpandFileName(Folder));
- Index := IndexOfFolder(FullPath);
- if Index >= 0 then
- Result := Items[Index]
- else
- begin
- Result := TTargetFolder.Create;
- Result.Folder := FullPath;
- Insert(0, Result);
- end;
- end;
-
- function TTargetFolderList.IsExcluded(const Folder, FileName: String): Boolean;
- var
- I: Integer;
- begin
- Result := False;
- for I := ExcludedFiles.Count - 1 downto 0 do
- if FileMatches(Folder, FileName, ExcludedFiles[I]) then
- begin
- Result := True;
- Exit;
- end;
- end;
-
- function TTargetFolderList.GetItems(Index: Integer): TTargetFolder;
- begin
- Result := TTargetFolder(inherited Items[Index]);
- end;
-
- { TTargetSearch }
-
- constructor TTargetSearch.Create(Criteria: TSearchCriteria);
- begin
- inherited Create;
- TargetFolders := TTargetFolderList.Create;
- Attribute := TAttributeCriteria.Create;
- TimeStamp := TDateTimeCriteria.Create;
- Size := TSizeCriteria.Create;
- Content := TContentCriteria.Create;
- PrepareTargetFolders(Criteria.Files);
- Attribute.Assign(Criteria.Attribute);
- TimeStamp.Assign(Criteria.TimeStamp);
- Size.Assign(Criteria.Size);
- Content.Assign(Criteria.Content);
- if Content.PhraseLen > 0 then
- Attribute.Attributes := Attribute.Attributes - [ffDirectory];
- end;
-
- destructor TTargetSearch.Destroy;
- begin
- TargetFolders.Free;
- Attribute.Free;
- TimeStamp.Free;
- Size.Free;
- Content.Free;
- inherited Destroy;
- end;
-
- procedure TTargetSearch.PrepareTargetFolders(FileCriteria: TFileCriteria);
-
- function CreateItemsList(ItemsText: String): TStringList;
- var
- DelimiterPos: Integer;
- begin
- Result := TStringList.Create;
- Result.Duplicates := dupIgnore;
- while ItemsText <> '' do
- begin
- DelimiterPos := Pos(Delimiter, ItemsText);
- if DelimiterPos = 0 then
- begin
- Result.Add(ItemsText);
- Break;
- end
- else
- begin
- Result.Add(Copy(ItemsText, 1, DelimiterPos - 1));
- Delete(ItemsText, 1, DelimiterPos);
- end;
- end;
- end;
-
- function CheckSubfolders(var Folder: String): Boolean;
- begin
- Result := FileCriteria.Subfolders;
- if Folder <> '' then
- begin
- case Folder[1] of
- IncSubfolders:
- begin
- Result := True;
- Delete(Folder, 1, 1);
- end;
- ExcSubfolders:
- begin
- Result := False;
- Delete(Folder, 1, 1);
- end;
- end;
- end;
- end;
-
- var
- I: Integer;
- Item: String;
- FileList: TStringList;
- FolderList: TStringList;
- ThisFolder: TTargetFolder;
- Subfolders: Boolean;
- begin
- TargetFolders.ExcludedFiles.Assign(FileCriteria.Excluded);
- // Processes Included property
- for I := 0 to FileCriteria.Included.Count - 1 do
- begin
- Item := FileCriteria.Included[I];
- Subfolders := CheckSubfolders(Item);
- ThisFolder := TargetFolders.AddFolder(ExtractFilePath(Item));
- ThisFolder.FileMasks.Add(ExtractFileName(Item));
- ThisFolder.Subfolders := Subfolders;
- end;
- // Processes FileName and Location properties
- FileList := CreateItemsList(FileCriteria.FileName);
- try
- FolderList := CreateItemsList(FileCriteria.Location);
- try
- for I := 0 to FolderList.Count - 1 do
- begin
- Item := FolderList[I];
- Subfolders := CheckSubfolders(Item);
- ThisFolder := TargetFolders.AddFolder(Item);
- ThisFolder.FileMasks.AddStrings(FileList);
- ThisFolder.Subfolders := Subfolders;
- end;
- finally
- FolderList.Free;
- end;
- finally
- FileList.Free;
- end;
- end;
-
- function TTargetSearch.Matches(const Folder: String;
- const SR: TSearchRec): Boolean;
- begin
- with SR.FindData do
- Result := Attribute.Matches(SR.Attr) and Size.Matches(SR.Size) and
- TimeStamp.Matches(ftCreationTime, ftLastWriteTime, ftLastAccessTime) and
- not TargetFolders.IsExcluded(Folder, SR.Name) and
- Content.Matches(Folder + SR.Name);
- end;
-
- { TSearchThread }
-
- type
- PSearchRec = ^TSearchRec;
- TSearchThread = class(TThread)
- private
- Owner: TFindFile;
- ThisFolder: String;
- ThisFolderIgnored: Boolean;
- MatchedSR: PSearchRec;
- procedure NotifyFolderChanged;
- procedure NotifyFileMatched;
- protected
- constructor Create(AOwner: TFindFile);
- procedure Execute; override;
- end;
-
- constructor TSearchThread.Create(AOwner: TFindFile);
- begin
- inherited Create(True);
- Owner := AOwner;
- FreeOnTerminate := True;
- Priority := Owner.ThreadPriority;
- OnTerminate := Owner.ThreadTerminated;
- Resume;
- end;
-
- procedure TSearchThread.NotifyFileMatched;
- begin
- Owner.DoFileMatch(ThisFolder, MatchedSR^);
- end;
-
- procedure TSearchThread.NotifyFolderChanged;
- begin
- ThisFolderIgnored := not Owner.DoFolderChange(ThisFolder);
- end;
-
- procedure TSearchThread.Execute;
-
- procedure SearchIn(const Path: String);
- var
- SR: TSearchRec;
- MaskIndex: Integer;
- begin
- ThisFolder := Path;
- Synchronize(NotifyFolderChanged);
- if ThisFolderIgnored then Exit;
- with Owner.ActiveTargetFolder do
- begin
- // Searches in the current folder for all file masks
- MaskIndex := FileMasks.Count;
- while not Terminated and (MaskIndex > 0) do
- begin
- Dec(MaskIndex);
- if not Terminated and (FindFirst(Path + FileMasks[MaskIndex], ValidFileAttr, SR) = 0) then
- begin
- repeat
- if (SR.Name <> '.') and (SR.Name <> '..') and Owner.IsAcceptable(Path, SR) then
- begin
- MatchedSR := @SR;
- Synchronize(NotifyFileMatched);
- end;
- until Terminated or (FindNext(SR) <> 0);
- FindClose(SR);
- end;
- end;
- // Searches in subfolders
- if Subfolders then
- begin
- if not Terminated and (FindFirst(Path + '*.*', ValidFileAttr, SR) = 0) then
- begin
- repeat
- if ((SR.Attr and faDirectory) = faDirectory) and
- (SR.Name <> '.') and (SR.Name <> '..')
- then
- SearchIn(Path + SR.Name + '\');
- until Terminated or (FindNext(SR) <> 0);
- FindClose(SR);
- end;
- end;
- end;
- end;
-
- var
- Index: Integer;
- begin
- Index := Owner.TargetSearch.TargetFolders.Count;
- while not Terminated and (Index > 0) do
- begin
- Dec(Index);
- Owner.ActiveTargetFolder := Owner.TargetSearch.TargetFolders[Index];
- SearchIn(Owner.ActiveTargetFolder.Folder);
- end;
- end;
-
- { TFindFile }
-
- constructor TFindFile.Create(AOwner: TComponent);
- begin
- inherited Create(AOwner);
- fCriteria := TSearchCriteria.Create;
- fThreaded := False;
- fThreadPriority := tpNormal;
- fAborted := False;
- fBusy := False;
- end;
-
- destructor TFindFile.Destroy;
- begin
- if Busy then
- begin
- Abort;
- repeat
- Application.ProcessMessages
- until Busy;
- end;
- fCriteria.Free;
- inherited Destroy;
- end;
-
- procedure TFindFile.Abort;
- begin
- if fBusy then
- begin
- fAborted := True;
- DoSearchAbort;
- if Assigned(SearchThread) then
- SearchThread.Terminate;
- end;
- end;
-
- procedure TFindFile.DoFileMatch(const Folder: String;
- const FileInfo: TSearchRec);
- begin
- if not Aborted and Assigned(fOnFileMatch) then
- fOnFileMatch(Self, Folder, FileInfo);
- end;
-
- function TFindFile.DoFolderChange(const Folder: String): Boolean;
- var
- IgnoreIt: Boolean;
- begin
- IgnoreIt := Aborted;
- if not Aborted and Assigned(fOnFolderChange) then
- fOnFolderChange(Self, Folder, IgnoreIt);
- Result := not IgnoreIt;
- end;
-
- procedure TFindFile.DoSearchBegin;
- begin
- if Assigned(fOnSearchBegin) then
- fOnSearchBegin(Self);
- end;
-
- procedure TFindFile.DoSearchFinish;
- begin
- if Assigned(fOnSearchFinish) and not (csDestroying in ComponentState) then
- fOnSearchFinish(Self);
- end;
-
- procedure TFindFile.DoSearchAbort;
- begin
- if Assigned(fOnSearchAbort) and not (csDestroying in ComponentState) then
- fOnSearchAbort(Self);
- end;
-
- procedure TFindFile.SearchForFiles;
-
- procedure SearchIn(const Path: String);
- var
- SR: TSearchRec;
- MaskIndex: Integer;
- begin
- if not DoFolderChange(Path) then Exit;
- with ActiveTargetFolder do
- begin
- // Searches in the current folder for all file masks
- MaskIndex := FileMasks.Count;
- while not Aborted and (MaskIndex > 0) do
- begin
- Dec(MaskIndex);
- if not Aborted and (FindFirst(Path + FileMasks[MaskIndex], ValidFileAttr, SR) = 0) then
- begin
- repeat
- if (SR.Name <> '.') and (SR.Name <> '..') and IsAcceptable(Path, SR) then
- DoFileMatch(Path, SR);
- until Aborted or (FindNext(SR) <> 0);
- FindClose(SR);
- end;
- end;
- // Searches in subfolders
- if Subfolders then
- begin
- if not Aborted and (FindFirst(Path + '*.*', ValidFileAttr, SR) = 0) then
- begin
- repeat
- if ((SR.Attr and faDirectory) = faDirectory) and
- (SR.Name <> '.') and (SR.Name <> '..')
- then
- SearchIn(Path + SR.Name + '\');
- until Aborted or (FindNext(SR) <> 0);
- FindClose(SR);
- end;
- end;
- end;
- end;
-
- var
- Index: Integer;
- begin
- Index := TargetSearch.TargetFolders.Count;
- while not Aborted and (Index > 0) do
- begin
- Dec(Index);
- ActiveTargetFolder := TargetSearch.TargetFolders[Index];
- SearchIn(ActiveTargetFolder.Folder);
- end;
- end;
-
- procedure TFindFile.InitializeSearch;
- begin
- fBusy := True;
- fAborted := False;
- TargetSearch := TTargetSearch.Create(Criteria);
- DoSearchBegin;
- end;
-
- procedure TFindFile.FinalizeSearch;
- begin
- DoSearchFinish;
- TargetSearch.Free;
- fBusy := False;
- end;
-
- procedure TFindFile.Execute;
- begin
- if not Busy then
- begin
- InitializeSearch;
- if Threaded then
- SearchThread := TSearchThread.Create(Self)
- else
- begin
- SearchForFiles;
- FinalizeSearch;
- end;
- end;
- end;
-
- function TFindFile.IsAcceptable(const Folder: String; const SR: TSearchRec): Boolean;
- begin
- Result := TargetSearch.Matches(Folder, SR)
- end;
-
- procedure TFindFile.ThreadTerminated(Sender: TObject);
- begin
- SearchThread := nil;
- FinalizeSearch;
- end;
-
- procedure TFindFile.SetCriteria(Value: TSearchCriteria);
- begin
- Criteria.Assign(Value);
- end;
-
- end.
-
-
-