As other mentioned, I think the bottleneck is the disk IO. So I present a solution, that run in two threads. In the first i do the filesearch and in the second the files will filtered. So the search and analyze is at the same time.
BUT: Time your code to find the your bottleneck.
TSearchFilterThread = class(TThread)
private
fFileQueue: TStringList;
fExtensionList: TStringList;
fCriticalSection: TCriticalSection;
fResultList: TStringList;
fNewDataInList: TSimpleEvent;
function getNextFileToProcess: string;
function matchFilter(const filename: string): boolean;
protected
procedure execute; override;
public
constructor create(searchForExtension: TStringList); reintroduce;
destructor destroy; override;
procedure appendFile(const filename: string);
procedure waitForEnd;
property Results: TStringlist read fResultList;
end;
procedure TSearchFilterThread.appendFile(const filename: string);
begin
fCriticalSection.Enter;
try
fFileQueue.Add(filename);
fNewDataInList.SetEvent;
finally
fCriticalSection.Leave;
end;
end;
constructor TSearchFilterThread.create(searchForExtension: TStringList);
begin
inherited create(true);
//To protected acces to the TStringList fFileQueue
fCriticalSection := TCriticalSection.Create;
fExtensionList := searchForExtension;
fExtensionList.Sorted := true;
fExtensionList.CaseSensitive := false;
fFileQueue := TStringList.Create;
//Event to notify workerthread, that new data available
fNewDataInList := TSimpleEvent.Create;
fNewDataInList.ResetEvent;
fResultList := TStringList.Create;
resume;
end;
destructor TSearchFilterThread.destroy;
begin
terminate;
fNewDataInList.SetEvent;
waitFor;
fResultList.Free;
fCriticalSection.Free;
fFileQueue.Free;
inherited;
end;
function TSearchFilterThread.getNextFileToProcess: string;
begin
fCriticalSection.Enter;
try
if fFileQueue.Count > 0 then begin
result := fFileQueue[0];
fFileQueue.Delete(0);
end
else
result := '';
finally
fCriticalSection.Leave;
end;
end;
function TSearchFilterThread.matchFilter(const filename: string): boolean;
var
extension: string;
begin
extension := ExtractFileExt(filename);
result := fExtensionList.IndexOf(extension) > -1;
end;
procedure TSearchFilterThread.execute;
const
INFINITE: longword = $FFFFFFFF;
var
fileName: string;
begin
while true do begin
fileName := getNextFileToProcess;
if fileName <> '' then begin
if matchFilter(filename) then
fResultList.Add(fileName);
end
else if not terminated then begin
fNewDataInList.WaitFor(INFINITE);
fNewDataInList.resetEvent;
end
else if terminated then
break;
end;
end;
procedure TSearchFilterThread.waitForEnd;
begin
Terminate;
fNewDataInList.SetEvent;
waitFor;
end;
The searchmethod that find all files and delegate the filtering to the thred
procedure FileSearch(const pathName: string; filter: TSearchFilterThread);
const
FileMask = '*.*';
var
Rec: TSearchRec;
Path: string;
begin
Path := IncludeTrailingPathDelimiter(pathName);
if FindFirst(Path + FileMask, faAnyFile - faDirectory, Rec) = 0 then
try
repeat
filter.appendFile(Path + rec.Name);
until FindNext(Rec) <> 0;
finally
SysUtils.FindClose(Rec);
end;
if FindFirst(Path + '*.*', faDirectory, Rec) = 0 then
try
repeat
if ((Rec.Attr and faDirectory) <> 0) and (Rec.Name <> '.') and
(Rec.Name <> '..') then
FileSearch(Path + Rec.Name, filter);
until FindNext(Rec) <> 0;
finally
FindClose(Rec);
end;
end;
And here the starter and resultpresenter:
procedure TForm1.startButtonClick(Sender: TObject);
var
searchFilter: TSearchFilterThread;
searchExtensions: TStringList;
path: string;
begin
path := 'c:\windows';
searchExtensions := TStringList.Create;
searchExtensions.Add('.doc');
searchExtensions.Add('.docx');
searchExtensions.Add('.ini');
searchFilter := TSearchFilterThread.create(searchExtensions);
try
FileSearch(path, searchFilter);
searchFilter.waitForEnd;
fileMemo.Lines := searchFilter.Results;
finally
searchFilter.Free;
searchExtensions.Free;
end;
end;
It might be a little oversized, but I want to code a little bit.