Home > Back-end >  Filestream Bytes not written properly
Filestream Bytes not written properly

Time:06-03

Why do I get the wrong output using the following code in RAD Studio 10.1?

var
  sPalette : string;
  mystream: TfileStream;
begin
  mystream := TfileStream.Create('C:\Data\test.bmp', fmCreate);
  sPalette := #1#2#3#4#5#6;
  mystream.WriteBuffer(Pointer(sPalette)^, Length(sPalette));
  mystream.Free;
end;

Got Output : 01 00 02 00 03 00

Expected output : 01 02 03 04 05 06

CodePudding user response:

In Delphi 2009 , string is a 16-bit, UTF-16 encoded UnicodeString. You are not taking into account that SizeOf(Char) is 2 bytes, not 1 byte as you are expecting. Length(string) is expressed in number of characters, not in number of bytes. Your string is 6 characters in length, but is 12 bytes in size. You are writing only the 1st 6 bytes of the string to your file. And since your string contains ASCII characters below #128, every other byte will be $00.

Use an 8-bit AnsiString instead, eg:

var
  sPalette : AnsiString;
  mystream: TFileStream;
begin
  mystream := TFileStream.Create('C:\Data\test.bmp', fmCreate);
  try
    sPalette := #1#2#3#4#5#6;
    mystream.WriteBuffer(Pointer(sPalette)^, Length(sPalette));
  finally
    mystream.Free;
  end;
end;

Or, use TEncoding to convert the Unicode string to an 8-bit byte encoding:

var
  sPalette : string;
  bytes: TBytes;
  mystream: TFileStream;
begin
  mystream := TFileStream.Create('C:\Data\test.bmp', fmCreate);
  try
    sPalette := #1#2#3#4#5#6;
    bytes := TEncoding.Default.GetBytes(sPalette);
    mystream.WriteBuffer(Pointer(bytes)^, Length(bytes));
  finally
    mystream.Free;
  end;
end;

Alternatively:

var
  sPalette : string;
  mystream: TStreamWriter;
begin
  mystream := TStreamWriter.Create('C:\Data\test.bmp', False, TEncoding.Default);
  try
    sPalette := #1#2#3#4#5#6;
    mystream.Write(sPalette);
  finally
    mystream.Free;
  end;
end;

Though, you really should not be using a string for binary data in the first place. Use a byte array instead, eg:

var
  bytes: TBytes;
  mystream: TFileStream;
begin
  mystream := TFileStream.Create('C:\Data\test.bmp', fmCreate);
  try
    SetLength(bytes, 6);
    bytes[0] := $1;
    ...
    bytes[5] := $6;
    mystream.WriteBuffer(Pointer(bytes)^, Length(bytes));
  finally
    mystream.Free;
  end;
end;

Or better, just use a TBitmap object, since you are writing to a .bmp file, eg:

var
  bmp: TBitmap;
begin
  bmp := TBitmap.Create;
  try
    ...
    bmp.SaveToFile('C:\Data\test.bmp');
  finally
    bmp.Free;
  end;
end;
  • Related