...search a file for a specified text?

Author: P. Below
Homepage: http://www.teamb.com

Category: Files

function ScanFile(const FileName: string;
  const forString: string;
  caseSensitive: Boolean): Longint;
  { returns position of string in file or -1, if not found }
const
  
BufferSize = $8001;  { 32K+1 bytes }
var
  
pBuf, pEnd, pScan, pPos: PChar;
  filesize: LongInt;
  bytesRemaining: LongInt;
  bytesToRead: Word;
  F: file;
  SearchFor: PChar;
  oldMode: Word;
begin
  
Result := -1;  { assume failure }
  
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;
       { scan the buffer. Problem: buffer may contain #0 chars! So we
         treat it as a concatenation of zero-terminated strings. }
      
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
       
{ no luck in this buffers load. We need to handle the case of
         the search string spanning two chunks of file now. We simply
         go back a bit in the file and read from there, thus inspecting
         some characters twice
       }
        
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 }

 

printed from
www.swissdelphicenter.ch
developers knowledge base