Почему вы используете TEncoding.Unicode
?TEncoding.UTF8
имело бы больше смысла.
В любом случае, это не проблема кодирования.То, что вы пытаетесь сделать, просто не будет работать так, как вы пытаетесь это сделать, потому что TStrings
данные имеют переменную длину и должны обрабатываться соответствующим образом.Тем не менее, TStrings
не сохраняет какой-либо конечный разделитель или информацию о размере в выходной поток.При загрузке в поток TStrings.LoadFromStream()
просто читает ВЕСЬ поток (в любом случае, все между текущим Position
и концом потока).Вот почему вы получаете потоковые ошибки при попытке чтения / записи любых не TStrings
данных после любых TStrings
данных.
Так же, как более ранний код , необходимый для сериализации 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);