delphi 未正确写入文件流字节

pkwftd7m  于 2022-11-04  发布在  其他
关注(0)|答案(1)|浏览(173)

为什么在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;

已获得输出:01 02 03 04 05 06
预期输出:01 02 03 04 05 06

qyswt5oh

qyswt5oh1#

在 Delphi 2009+中,string是一个16位,UTF-16编码的UnicodeString。您没有考虑到SizeOf(Char)是2个字节,而不是您所期望的1个字节。Length(string)是以字符数表示的,而不是以字节数表示的。您的字符串长度为6个字符,但大小为12个字节。您只将string的前6个字节写入文件。由于您的string包含#128以下的ASCII字符,因此每隔一个字节将写入$00
请改用8位AnsiString,例如:

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;

或者,使用TEncoding将Unicode字符串转换为8位字节编码:

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;

或者:

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;

不过,对于二进制数据,首先不应该使用string,而应该使用字节数组,例如:

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;

或者更好的方法是使用TBitmap对象,因为您正在写入.bmp文件,例如:

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

相关问题