你为什么使用TEncoding.Unicode? TEncoding.UTF8 会更有意义。
无论如何,这不是编码问题。您尝试做的事情根本不会像您尝试做的那样工作,因为TStrings 数据是可变长度的,需要相应地处理。但是,TStrings 不会将任何类型的终止分隔符或大小信息保存到输出流中。在流中加载时,TStrings.LoadFromStream() 只是读取整个流(好吧,无论如何,当前 Position 和 End-Of-Stream 之间的所有内容)。这就是为什么在任何TStrings 数据之后尝试读/写任何非TStrings 数据时出现流错误的原因。
就像the earlier code 需要将String 数据和其他可变长度数据序列化为平面格式以了解一个字段的结束位置和下一个字段的开始位置一样,您也需要序列化TStrings 数据。
一种选择是先将TStrings 对象保存到中间TMemoryStream,然后将该流的Size 写入您的输出流,然后再写入TMemoryStream 的数据。稍后加载时,首先读取Size,然后将指定的字节数读入中间TMemoryStream,然后将该流加载到您的接收TStrings对象中:
procedure WriteInt64ToStream(Stream: TStream; Value: Int64);
begin
Stream.WriteBuffer(Value, Sizeof(Value));
end;
function ReadInt64FromStream(Stream: TStream): Int64;
begin
Stream.ReadBuffer(Result, Sizeof(Result));
end;
procedure WriteStringsToStream(Stream: TStream; Values: TStrings);
var
MS: TMemoryStream;
Size: Int64;
begin
MS := TMemoryStream.Create;
try
Values.SaveToStream(MS, TEncoding.UTF8);
Size := MS.Size;
WriteInt64ToStream(Stream, Size);
if Size > 0 then
begin
MS.Position := 0;
Stream.CopyFrom(MS, Size);
end;
finally
MS.Free;
end;
end;
procedure ReadStringsFromStream(Stream: TStream; Values: TStrings);
var
MS: TMemoryStream;
Size: Int64;
begin
Size := ReadInt64FromStream(Stream);
MS := TMemoryStream.Create;
try
if Size > 0 then
begin
MS.CopyFrom(Stream, Size);
MS.Position := 0;
end;
Values.LoadFromStream(MS, TEncoding.UTF8);
finally
MS.Free;
end;
end;
另一种选择是将TStrings 对象中字符串元素的数量写入输出流,然后写入各个字符串:
procedure WriteStringsToStream(Stream: TStream; Values: TStrings);
var
Count, I: Integer;
begin
Count := Values.Count;
WriteIntegerToStream(Stream, Count);
for I := 0 to Count-1 do
WriteStringToStream(Stream, Values[I]);
end;
procedure ReadStringsFromStream(Stream: TStream; Values: TStrings);
var
Count, I: Integer;
begin
Count := ReadIntegerFromStream(Stream);
if Count > 0 then
begin
Values.BeginUpdate;
try
for I := 0 to Count-1 do
Values.Add(ReadStringFromStream(Stream));
finally
Values.EndUpdate;
end;
end;
end;
无论哪种方式,您都可以在流式传输个人记录时执行此操作:
WriteIntegerToStream(SavingStream, Version);
WriteStringToStream(SavingStream, Name);
...
WriteStringsToStream(SavingStream, ColList1);
WriteStringsToStream(SavingStream, ColList2);
WriteBooleanToStream(SavingStream, ReadyToRun);
Version := ReadIntegerFromStream(SavingStream);
Name := ReadStringFromStream(SavingStream);
...
ReadStringsFromStream(SavingStream, ColList1);
ReadStringsFromStream(SavingStream, ColList2);
ReadyToRun := ReadBooleanFromStream(SavingStream);