To search for a specific substring within any type of file, we can use this rather complex function.
As a parameter, just pass the filename, substring you want to search and finally set true or false, if you want to search case sensitive.
function ScanFile(const filename: string; const forString: string; caseSensitive: Boolean ): LongInt;
const BufferSize= $8001;
var
pBuf, pEnd, pScan, pPos: Pchar;
filesize: LongInt;
bytesRemaining: LongInt;
bytesToRead: Integer;
F: File;
SearchFor: Pchar;
oldMode: Word;
begin
result := -1;
if (Length(forString) = 0) or (Length(filename) = 0) then Exit;
SearchFor := nil;
pBuf := nil;
AssignFile(F, filename);
oldMode := FileMode;
FileMode := 0;
Reset(F, 1);
FileMode := oldMode;
try
SearchFor := StrAlloc(Length(forString) + 1);
StrPCopy(SearchFor, forString);
if not caseSensitive then AnsiUpper(SearchFor);
GetMem(pBuf, BufferSize);
filesize := System.Filesize(F);
bytesRemaining := filesize;
pPos := nil;
while bytesRemaining > 0 do
begin
if bytesRemaining >= BufferSize then bytesToRead := Pred(BufferSize)
else bytesToRead := bytesRemaining;
BlockRead(F, pBuf^, bytesToRead, bytesToRead);
pEnd := @pBuf[bytesToRead];
pEnd^:= #0;
pScan := pBuf;
while pScan < pEnd do
begin
if not caseSensitive then AnsiUpper(pScan);
pPos := StrPos(pScan, SearchFor);
if pPos <> nil then
begin
result := FileSize - bytesRemaining + LongInt(pPos) - LongInt(pBuf);
break;
end;
pScan := StrEnd(pScan);
Inc(pScan);
end;
if pPos <> nil then break;
bytesRemaining := bytesRemaining - bytesToRead;
if bytesRemaining > 0 then
begin
seek(F, FilePos(F) - Length(forString));
bytesRemaining := bytesRemaining + Length(forString);
end;
end;
finally
CloseFile(F);
if SearchFor <> nil then StrDispose(SearchFor);
if pBuf <> nil then FreeMem(pBuf, BufferSize);
end;
end;
...
procedure TForm1.Button1Click(Sender: TObject);
var position: integer;
begin
position := ScanFile('c:filename.txt', 'searchphrase', true);
if position <> -1 then ShowMessage('Text found at position: ' + IntToStr(position))
else ShowMessage('Not found');
end;