Jump to content
William23668

Reading a binary file hangup without error

Recommended Posts

Hi

 

I was able to read the file byte by byte but the app hangup/not responding I dont know why ? Here is the code:

 

 

var
  AFile: TFileStream;
  BR: TBinaryReader;
  MyByteArray: TBytes;
  mstr: String;
  i: integer;
begin
  AFile := TFileStream.Create(filename, fmOpenRead);
  BR := TBinaryReader.Create(AFile, TEncoding.Unicode, false);
  try
    SetLength(MyByteArray, AFile.Size);

    // Get the whole file contents into the byte array
    MyByteArray := BR.ReadBytes(AFile.Size);

    for i := low(MyByteArray) to High(MyByteArray) do begin
      SetString(mstr, PAnsiChar(@MyByteArray[i]), Length(MyByteArray));
      RichEdit1.Text := RichEdit1.Text + mstr;
    end;

    BR.Close;
  finally

    BR.Free;
    AFile.Free;
  end;
end;

 

Share this post


Link to post

I see several issues with that code:

 

1. your SetLength() is useless, because the subsequent ReadBytes() is completely replacing your allocated array with a different array allocates by ReadBytes().

 

2. your SetString() is wrong, for two reasons:

 

   a. String is UnicodeString in D2009+, which you are clearly using due to TEncoding, which was also introduced in D2009.  You are trying to populate the UnicodeString with AnsiChar data, but there is no overload of SetString() for that.  You can only populate a UnicodeString with WideChar data. For AnsiChar data, you need to use AnsiString instead.

 

   b. You are advancing a PAnsiChar pointer through the byte array, but you are giving the array's whole length to SetString(), which means SetString() is going to read beyond the end of the array into surrounding memory after the 1st loop iteration.  Since you are trying to convert each Byte into an (Ansi)String, you would need to use 1 for the SetString() length instead.

 

3. appending strings to the RichEdit1.Text property in a loop is VERY inefficient. It requires reading the RichEdit's entire content into a String in memory, then expanding that String in memory with appended data, then replacing the RichEdit's entire content with the new string. A much more efficient way to append strings to a RichEdit's content is to use its SelText property instead, eg:

RichEdit1.SelStart := RichEdit1.GetTextLen;
RichEdit1.SelLength := 0;
RichEdit1.SelText := ...;

But even that is not the best approach in this situation.  Since you are trying to display a byte array as-is in the RichEdit as text, you may as well just assign the RichEdit.Text property 1 time with the entire array as 1 string, no loop needed at all, eg:

var
  AFile: TFileStream;
  BR: TBinaryReader;
  MyByteArray: TBytes;
  mstr: AnsiString;
begin
  AFile := TFileStream.Create(filename, fmOpenRead);
  BR := TBinaryReader.Create(AFile, TEncoding.Unicode, false);
  try
    // Get the whole file contents into the byte array
    MyByteArray := BR.ReadBytes(AFile.Size);

    SetString(mstr, PAnsiChar(@MyByteArray[0]), Length(MyByteArray));
    RichEdit1.Text := mstr;

    // or: RichEdit1.Text := TEncoding.ANSI.GetString(MyByteArray);

    BR.Close;
  finally
    BR.Free;
    AFile.Free;
  end;
end;

In which case, you may as well just get rid of the TBinaryReader, as you can read bytes from the TFileStream directly:

var
  AFile: TFileStream;
  MyByteArray: TBytes;
  mstr: AnsiString;
begin
  AFile := TFileStream.Create(filename, fmOpenRead);
  try
    SetLength(MyByteArray, AFile.Size);

    // Get the whole file contents into the byte array
    AFile.ReadBuffer(MyByteArray[0], SetLength(MyByteArray));

    SetString(mstr, PAnsiChar(@MyByteArray[0]), Length(MyByteArray));
    RichEdit1.Text := mstr;

    // or: RichEdit1.Text := TEncoding.ANSI.GetString(MyByteArray);

  finally
    AFile.Free;
  end;
end;

In which case, you can just get rid of the TFileStream altogether, too:

RichEdit1.Text := TFile.ReadAllText(filename, TEncoding.ANSI);

Or

RichEdit1.Lines.LoadFromFile(filename, TEncoding.ANSI);

 

Edited by Remy Lebeau
  • Thanks 1

Share this post


Link to post

@Remy Lebeau

 

Many thanks I learned many things now. I just need to read byte by byte for processing later.

Edited by William23668

Share this post


Link to post

You aren't going to be able to display the contents of a binary file in a rich edit control like this. If you want a hex editor, then display each byte as hex. 

  • Thanks 1

Share this post


Link to post
11 hours ago, David Heffernan said:

You aren't going to be able to display the contents of a binary file in a rich edit control like this. If you want a hex editor, then display each byte as hex. 

Just for learning why the app stop responding ? if I used richedit LoadFromStream it load fine.

Share this post


Link to post
8 hours ago, William23668 said:

Just for learning why the app stop responding ? if I used richedit LoadFromStream it load fine.

But it's not text, you can't treat it as text, and there's nothing to learn. What you should learn is how text is encoded. Why not do that? 

  • Like 1

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×