Запись строк в TMemoryStream

Я прочитал здесь много обсуждений относительно записи строк в TMemoryStream, сохранения в файл и чтения строк обратно в TMemoryStream.

Я не знаю, что я здесь сделал не так, но либо мои SaveData, либо мои LoadData неверны. Я могу проверить значение Title перед вызовом SaveData, и оно содержит то, что я ожидал. Однако когда я вызываю LoadData и проверяю значение Title, это мусор. Кто-нибудь может сказать мне, что я сделал не так, пожалуйста

procedure SaveData(FileName: TFileName);
var
 MemStr: TMemoryStream;
 Title: String;
begin
 MemStr:= TMemoryStream.Create;
try
 MemStr.Seek(0, soFromBeginning);
 WriteStreamStr( MemStr, TItle );
 MemStr.SaveToFile(FileName);
finally
 MemStr.Free;
end;
end;

procedure LoadData(FileName: TFileName);
var
 MemStr: TMemoryStream;
 Title: String;
begin
 MemStr:= TMemoryStream.Create;
 try
  MemStr.LoadFromFile(FileName);
  MemStr.Seek(0, soFromBeginning);
  Title := ReadStreamStr( MemStr );
 finally
   MemStr.Free;
  end;
end;



procedure WriteStreamInt(Stream : TStream; Num : integer);
 {writes an integer to the stream}
begin
 Stream.WriteBuffer(Num, SizeOf(Integer));
end;

procedure WriteStreamStr(Stream : TStream; Str : string);
 {writes a string to the stream}
var
 StrLen : integer;
begin
 {get length of string}
 StrLen := Length(Str);
 {write length of string}
 WriteStreamInt(Stream, StrLen);
 if StrLen > 0 then
 {write characters}
 Stream.Write(Str[1], StrLen);
end;


function ReadStreamInt(Stream : TStream) : integer;
 {returns an integer from stream}
begin
 Stream.ReadBuffer(Result, SizeOf(Integer));
end;

function ReadStreamStr(Stream : TStream) : string;
 {returns a string from the stream}
var
 LenStr : integer;
begin
 Result := '';
 {get length of string}
 LenStr := ReadStreamInt(Stream);
 {set string to get memory}
 SetLength(Result, LenStr);
 {read characters}
 Stream.Read(Result[1], LenStr);
end;

person JakeSays    schedule 11.02.2013    source источник
comment
Почему бы тебе не попробовать TStringStream?   -  person TLama    schedule 11.02.2013
comment
Или попробуйте TStringList.SaveToFile / LoadFromFile?   -  person iamjoosy    schedule 11.02.2013
comment
Да, весь код кажется бессмысленным, учитывая, что TStrings имеет SaveToStream и LoadFromStream. И если это не идеально подходит для реального приложения, тогда классы чтения / записи сделают эту работу.   -  person David Heffernan    schedule 11.02.2013
comment
Извините, я должен был упомянуть об этом - потому что в конечном итоге я буду сохранять больше, чем просто строки.   -  person JakeSays    schedule 11.02.2013
comment
В этом случае вам понадобятся классы читателя / писателя. Вы заново изобретаете колесо, и ваше колесо уже не такое круглое, как у RTL!   -  person David Heffernan    schedule 11.02.2013
comment
См. Также stackoverflow.com/a/733322/33732   -  person Rob Kennedy    schedule 11.02.2013
comment
Стоит упомянуть, хотя, вероятно, это не ваша проблема - в зависимости от версии Delphi иногда вывод текста мусора является результатом неправильной записи / чтения строковых данных Unicode.   -  person    schedule 11.02.2013


Ответы (1)


Когда вы используете

Stream.Write(Str[1], StrLen);

вы записываете в поток первые StrLen байта. Но строковые данные (unicode) на самом деле составляют StrLen * SizeOf(Char) байта (вы должны учитывать размер типа char). Итак, должно работать следующее:

Stream.Write(Str[1], StrLen * SizeOf(Str[1]));

То же самое при чтении данных из потока.

person ain    schedule 11.02.2013
comment
ByteLength(Str) существует для этого - person David Heffernan; 11.02.2013