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;