9

I have read alot of discussions on here regarding writing strings to a TMemoryStream and saving to file and reading the strings back in to TMemoryStream

I dont know what I have done wrong here, but either my SaveData or my LoadData is wrong. I can check the value of Title before I call SaveData and it holds what I expect. However, when I call LoadData and check the value of Title, it is garbage. Can anyone tell me what I have done wrong please

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;
JakeSays
  • 2,048
  • 8
  • 29
  • 43
  • 2
    Why don't you give a try to `TStringStream` ? – TLama Feb 11 '13 at 15:28
  • 1
    Or give TStringList.SaveToFile / LoadFromFile a try ? – iamjoosy Feb 11 '13 at 15:35
  • Yes, all the code seems pointless given that `TStrings` has `SaveToStream` and `LoadFromStream`. And if that's not a perfect fit for the real application, then the reader/writer classes will do the job. – David Heffernan Feb 11 '13 at 15:44
  • Sorry, I should have mention that - its because I will eventually be saving more than just Strings. – JakeSays Feb 11 '13 at 16:06
  • 1
    In which case, you need the reader/writer classes. You are re-inventing the wheel, and your wheel isn't as round as the one in the RTL! – David Heffernan Feb 11 '13 at 16:07
  • 1
    See also http://stackoverflow.com/a/733322/33732 – Rob Kennedy Feb 11 '13 at 17:04
  • Worth a mention though likely not your issue - depending on Delphi version, sometimes the "garbage" text output is a result of incorrectly writing/reading unicode string data. –  Feb 11 '13 at 17:56

1 Answers1

25

When you use

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

you're writing first StrLen bytes to the stream. But the (unicode)string data is actually StrLen * SizeOf(Char) bytes (you have to take the size of the char type into account). So following should work:

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

Same when reading data back from stream.

ain
  • 22,394
  • 3
  • 54
  • 74