文件流字节未正确写入
Filestream Bytes not written properly
为什么在 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 00 02 00 03 00
预期输出:01 02 03 04 05 06
在 Delphi 2009+ 中,string
是一个 16 位、UTF-16 编码的 UnicodeString
。您没有考虑到 SizeOf(Char)
是 2 个字节,而不是您期望的 1 个字节。 Length(string)
是用字符数表示的,不是字节数。您的字符串长度为 6 个字符,但大小为 12 个字节。您只将 string
的前 6 个字节写入您的文件。由于您的 string
包含 #128
以下的 ASCII 字符,每隔一个字节将是 [=22=]
.
改用 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] := ;
...
bytes[5] := ;
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;
为什么在 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 00 02 00 03 00
预期输出:01 02 03 04 05 06
在 Delphi 2009+ 中,string
是一个 16 位、UTF-16 编码的 UnicodeString
。您没有考虑到 SizeOf(Char)
是 2 个字节,而不是您期望的 1 个字节。 Length(string)
是用字符数表示的,不是字节数。您的字符串长度为 6 个字符,但大小为 12 个字节。您只将 string
的前 6 个字节写入您的文件。由于您的 string
包含 #128
以下的 ASCII 字符,每隔一个字节将是 [=22=]
.
改用 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] := ;
...
bytes[5] := ;
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;