Read bytes from file at desired position with Inno Setup

前端 未结 1 666
面向向阳花
面向向阳花 2020-12-06 15:06

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

相关标签:
1条回答
  • 2020-12-06 16:04

    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.

    0 讨论(0)
提交回复
热议问题