Delphi 2009及更高版本使用unicode字符串作为其默认字符串类型。据我所知,unicode char实际上是16位值或2个字节(注意:我知道有可能有3或4个字节的char,但让我们考虑最常见的情况)。但是我发现TStringStream对于操作这个字符串不是很可靠。例如,TStringStream.Size属性返回字符串的长度,而我认为它应该返回包含字符串的字节数。好的,您可以自己调整它,但最让我困惑的是:TStringStream不能可靠地读取或写入缓冲区。
请检查以下代码(这是一个DUnit测试并始终失败)。请告诉我问题所在(我在测试代码时使用的是D2010)。
procedure TestTCPackage.TestStringStream;
const
cCount = 10;
cOrdMaxChar = Ord(High(Char));
var
B: Pointer;
SW, SR: TStringStream;
T: string;
i, j, k : Integer;
vStrings: array [0..cCount-1] of string;
begin
RandSeed := GetTickCount;
for i := 0 to cCount - 1 do
begin
j := Random(100) + 1;
SetLength(vStrings[i], j);
for k := 1 to j do
// fill string with random char (but no #0)
vStrings[i][k] := Char(Random(cOrdMaxChar-1) + 1);
end;
for i := 0 to cCount - 1 do
begin
SW := TStringStream.Create(vStrings[i]);
try
GetMem(B, SW.Size * SizeOf(Char));
try
SW.Read(B^, SW.Size * SizeOf(Char));
SR := TStringStream.Create;
try
SR.Write(B^, SW.Size * SizeOf(Char));
SR.Position := 0;
// check the string in the TStringStream with original value
Check(SR.DataString = vStrings[i]);
finally
SR.Free;
end;
finally
FreeMem(B);
end;
finally
SW.Free;
end;
end;
end;
注意:我已经尝试使用TMemoryStream的实例作为读取/写入缓冲区的中介,并使用TStringStream的CopyFrom来读取具有相同失败效果的TMemoryStream的内容。
答案 0 :(得分:5)
Unicode字符串不用于数据存储;使用TBytes
。 TStringStream
使用其关联的编码(Encoding
属性)来编码使用WriteString
传入的字符串,并解码使用ReadString
或DataString
属性读取的字符串。
答案 1 :(得分:5)
在阅读this post(并感谢提供该问题答案的Serg)和Barry Kelly的回答后,我发现了问题。 TStringStream实际上默认使用ASCII / ansistring编码。因此,即使您的默认字符串类型是unicode,除非您特意告诉它,否则它将不使用unicode编码。我个人认为这很奇怪。也许是为了更容易转换旧代码。
所以你必须 专门设置TStringStream的编码 到TEncoding.Unicode来正确操作unicode字符串。
这是我通过DUnit测试的修改后的代码:
procedure TestTCPackage.TestStringStream;
const
cCount = 10;
cOrdMaxChar = Ord(High(Char));
var
B: Pointer;
SW, SR: TStringStream;
i, j, k : Integer;
vStrings: array [0..cCount-1] of string;
begin
RandSeed := GetTickCount;
for i := 0 to cCount - 1 do
begin
j := Random(100) + 1;
SetLength(vStrings[i], j);
for k := 1 to j do
// fill string with random char (but no #0)
vStrings[i][k] := Char(Random(cOrdMaxChar-1) + 1);
end;
for i := 0 to cCount - 1 do
begin
SW := TStringStream.Create(vStrings[i], ***TEncoding.Unicode***);
try
GetMem(B, SW.Size);
try
SW.ReadBuffer(B^, SW.Size);
SR := TStringStream.Create('', ***TEncoding.Unicode***);
try
SR.WriteBuffer(B^, SW.Size);
SR.Position := 0;
// check the string in the TStringStream with original value
Check(SR.DataString = vStrings[i]);
finally
SR.Free;
end;
finally
FreeMem(B);
end;
finally
SW.Free;
end;
end;
end;
最后注意:Unicode会咬人! :d