I want to open a 50 MB binary file and read only the last 4 bytes and convert it to string for some purpose.
The only way I found to do it now is using LoadStr
You can use TFileStream
support class:
TStream = class(TObject)
function Read(Buffer: String; Count: Longint): Longint;
function Write(Buffer: String; Count: Longint): Longint;
function Seek(Offset: Longint; Origin: Word): Longint;
procedure ReadBuffer(Buffer: String; Count: Longint);
procedure WriteBuffer(Buffer: String; Count: Longint);
function CopyFrom(Source: TStream; Count: Longint): Longint;
property Position: Longint; read write;
property Size: Longint; read write;
end;
THandleStream = class(TStream)
constructor Create(AHandle: Integer);
property Handle: Integer; read;
end;
TFileStream = class(THandleStream)
constructor Create(Filename: String; Mode: Word);
end;
Use the .Seek(-4, soFromEnd)
property to seek the read pointer to the desired position.
A complication is that the TStream
works with characters not bytes, so you have to convert Unicode strings that your read back to bytes.
When reading just four bytes, it's way easier to read byte by byte, preventing any multibyte conversions:
procedure ReadFileEnd;
var
Stream: TFileStream;
Buffer: string;
Count: Integer;
Index: Integer;
begin
Count := 4;
Stream := TFileStream.Create('my_binary_file.dat', fmOpenRead);
try
Stream.Seek(-Count, soFromEnd);
SetLength(Buffer, 1);
for Index := 1 to Count do
begin
Stream.ReadBuffer(Buffer, 1);
Log(Format('Byte %2.2x: %2.2x', [Index, Ord(Buffer[1])]));
end;
finally
Stream.Free;
end;
end;
Here's a generic alternative from by @TLama that efficiently works for arbitrary large read:
https://pastebin.com/nzGEdXVj
By the way, for me LoadStringFromFile function seems to be efficient enough to load 50 MB file. It takes only 40 ms.