Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Open Binary File, Find /Replace Text?

721 views
Skip to first unread message

Bob

unread,
Aug 10, 2003, 5:03:06 AM8/10/03
to
How do I open a binary file, then find and replace text? I've tried using
TStringList.LoadFromFile, then using "pos" to find text but there's no text
in the stringlist variable after the LoadFromFile. If I use "handle :=
FileOpen()" I cant seem to find a 'handle.search' function to find/replace
text.

Thanks, -Bob


Maarten Wiltink

unread,
Aug 10, 2003, 5:38:49 AM8/10/03
to
Bob wrote in message ...


Handle.Search is a bit overoptimistic. Merely opening a file
does not read in the contents and it doesn't present you with
magical find/replace functionality. If you were to read the
file contents into a string buffer, Pos would work on that.

As for TStrings.LoadFromFile, loading binary data into a string
buffer is unlikely to work well. It's quite possible that the
string will be truncated after the first nul character. But you
don't say how exactly you're trying to get at the text anyway.
Guessing from that Handle.Search, you may have a glitch there,
too.

Groetjes,
Maarten Wiltink

J French

unread,
Aug 10, 2003, 8:14:29 AM8/10/03
to

If you are happy reading the file 'all in one go' into a TStringList,
then you should have no worries about reading it into a String

More after sample code :-

Const FileName = 'c:\t\test.dat';
Const TestData = 'ABCDEFGHIJKTESTDATA';

procedure TForm1.Button1Click(Sender: TObject);
Var
FS :TFileStream;
S :String;
begin
// Create a file - if necessary
If FileExists( FileName ) = False Then
Begin
FS := TFileStream.Create( FileName, fmCreate );
FS.Position := 0;
S := TestData;
FS.Write( S[1], Length( S ) );
FS.Free;
ShowMessage( 'Created:' + S );
End;

// So we definitely have a file by now
FS := TFileStream.Create( FileName, fmOpenReadWrite );
FS.Position := 0; // not really needed
SetLength( S, FS.Size );
FS.Read( S[1], FS.Size );

// Replace
S := StringReplace( S, 'A', '{A}', [rfReplaceAll] );

// Put back to Disk
FS.Position := 0; // essential
FS.Write( S[1], Length( S ) );
FS.Size := Length( S ); // We may have shortened the file
FS.Free;
//
ShowMessage( 'New Data:' + S );
end;

// ---- End of Code ---

You could have done just the same using FileOpen, FileRead, FileWrite

Note that the Handle that they use is a DOS style File Handle, nothing
to do with Windows Handles

Also, unless you are absolutely certain that the file will be fairly
small, it is incredibly bad practise to 'wolf' an entire file into
memory.

That makes things a bit more complicated, but the use of Pos(), Move()
and Delete() in conjunction with two largish Strings should get round
that inconvenience. (Don't use String replace on partial strings)

HTH

Bob

unread,
Aug 11, 2003, 5:10:26 AM8/11/03
to
This worked great except for

S := StringReplace( S, 'A', '{A}', [rfReplaceAll] );
Dont know why... I test it with sample data and it worked fine but when used
on the small binary file it couldn't find the text?

-Bob

J French

unread,
Aug 11, 2003, 1:44:47 PM8/11/03
to
On Mon, 11 Aug 2003 09:10:26 GMT, "Bob" <newsg...@pless.net> wrote:

>This worked great except for
> S := StringReplace( S, 'A', '{A}', [rfReplaceAll] );
>Dont know why... I test it with sample data and it worked fine but when used
>on the small binary file it couldn't find the text?
>

RTFM

- or at least the File

J French

unread,
Aug 12, 2003, 3:20:24 AM8/12/03
to

Apologies - you were quite right

I've just checked
- StringReplace appears to use AnsiStrPos which is one of those
idiotic #0 terminated string routines

This is basically a bug in the Delphi Library

StringReplace does not handle #0 properly
- it bugs out after the first #0

Here is a proper alternative

( See StrReplaceStr below )

I suggest that you run it through a few tests, as I cut it out of my
existing libraries


{#################################################################

Result := InStr( 2, 'ABCDEF', 'BCD' ) rev: 20/6/02 JF
}
Function InStr( Start:Integer; Const BigStr,SmallStr:String):Integer;
Var
L9, L8, Max, P: Integer;
BigL, SmallL: Integer;
C : Char;
Begin
Result := 0; // Set Default

// Should be illegal
If Start <= 0 Then
Start := 1;

// Take String Lengths
BigL := Length( BigStr );
SmallL := Length( SmallStr );

// '' Target always returns 0
If BigL = 0 Then
Exit;

// '' Convention returns Start
If SmallL = 0 Then
Begin
Result := Start;
Exit;
End;

// Find last possible Start pos
Max := BigL - SmallL + 1;
If Max < Start Then
Exit;

// Take First Char of Search String
C := SmallStr[1];

// Hunt Forwards for a match
For L9 := Start To Max Do
If BigStr[L9] = C Then // If first Char Found
Begin
P := L9 + SmallL - 1;
For L8 := SmallL DownTo 2 Do // Scan Backwards
Begin
If BigStr[P] <> SmallStr[L8] Then
Break;
P := P - 1;
End;
// Success - we know first Char matches
If P = L9 Then
Begin
Result := L9;
Break;
End;
End;

End;{InStr}

{
########################################################################

also see: SysUtils.StringReplace - which fails on #0

}
Function StrReplaceStr( Const Tgt, OldStr, NewStr :String ):String ;
Var
Q, L : Integer ;
S : String ;
Begin


If OldStr = '' Then // Nasty Error
Begin
Result := Tgt ;
Exit;
End;

L := Length( OldStr ) ;
S := Tgt ;

Q := 1 ;
Q := Instr( Q, S, OldStr ) ;
While Q > 0 Do
Begin
S := Copy( S, 1, Q-1 ) + NewStr + Copy( S, Q + L, MAXINT ) ;
Q := Q + Length( NewStr ) ;
Q := Instr( Q, S, OldStr ) ;
End; {While}

Result := S ;

End; {StrReplaceStr}


Const FileName = 'c:\t\test.dat';

Const TestData = 'ABCDE'#0'FGHIJK'#1'TESTDATA';

procedure TForm1.Button1Click(Sender: TObject);
Var
FS :TFileStream;
S :String;
begin
// Create a file - if necessary
If FileExists( FileName ) = False Then
Begin
FS := TFileStream.Create( FileName, fmCreate );
FS.Position := 0;
S := TestData;
FS.Write( S[1], Length( S ) );
FS.Free;
ShowMessage( 'Created:' + S );
End;

// So we definitely have a file by now
FS := TFileStream.Create( FileName, fmOpenReadWrite );
FS.Position := 0; // not really needed
SetLength( S, FS.Size );
FS.Read( S[1], FS.Size );

// Replace
S := StrReplaceStr( S, 'A', '{A}'#0 );

0 new messages