Searching for string within a file

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;

Leave a Reply