...how to search a file for a string?

Author: Adapted from P. Below

Category: Files

{
  ScanFile searches for a string in a file and returns the position of the string
  in the file or -1, if not found.

  ScanFile sucht in einer Datei nach dem Vorkommen
  eines bestimmten Strings und gibt bei Erfolg die Position zurück, wo der String
  gefunden wurde.
}

function ScanFile(const FileName: string;
  const forString: string;
  caseSensitive: Boolean): Longint;
const
  
BufferSize = $8001;  { 32K+1 bytes }
var
  
pBuf, pEnd, pScan, pPos: PChar;
  filesize: LongInt;
  bytesRemaining: LongInt;
  bytesToRead: Integer;
  F: file;
  SearchFor: PChar;
  oldMode: Word;
begin
  
{ assume failure }
  
Result := -1;
  if (Length(forString) = 0) or (Length(FileName) = 0) then Exit;
  SearchFor := nil;
  pBuf      := nil;
  { open file as binary, 1 byte recordsize }
  
AssignFile(F, FileName);
  oldMode  := FileMode;
  FileMode := 0;    { read-only access }
  
Reset(F, 1);
  FileMode := oldMode;
  try { allocate memory for buffer and pchar search string }
    
SearchFor := StrAlloc(Length(forString) + 1);
    StrPCopy(SearchFor, forString);
    if not caseSensitive then  { convert to upper case }
      
AnsiUpper(SearchFor);
    GetMem(pBuf, BufferSize);
    filesize       := System.Filesize(F);
    bytesRemaining := filesize;
    pPos           := nil;
    while bytesRemaining > 0 do
    begin
      
{ calc how many bytes to read this round }
      
if bytesRemaining >= BufferSize then
        
bytesToRead := Pred(BufferSize)
      else
        
bytesToRead := bytesRemaining;
      { read a buffer full and zero-terminate the buffer }
      
BlockRead(F, pBuf^, bytesToRead, bytesToRead);
      pEnd  := @pBuf[bytesToRead];
      pEnd^ := #0;
      pScan := pBuf;
      while pScan < pEnd do
      begin
        if not 
caseSensitive then { convert to upper case }
          
AnsiUpper(pScan);
        pPos := StrPos(pScan, SearchFor);  { search for substring }
        
if pPos <> nil then
        begin 
{ Found it! }
          
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{ While }
  
finally
    
CloseFile(F);
    if SearchFor <> nil then StrDispose(SearchFor);
    if pBuf <> nil then FreeMem(pBuf, BufferSize);
  end;
end{ ScanFile }


// Search in autoexec.bat for "keyb" with case insensitive
// In der autoexec.bat nach "keyb" suchen

procedure TForm1.Button1Click(Sender: TObject);
var
  
Position: integer;
begin
  
Position := ScanFile('c:\autoexec.bat', 'keyb', False);
  ShowMessage(IntToStr(Position));
end;

 

printed from
www.swissdelphicenter.ch
developers knowledge base