We help IT Professionals succeed at work.

Write/Read Strings to stream!

brainware
brainware asked
on
Hmm wondering why this aint working ...

Procedure TMainform.SaveStringToStream(Const S : TFileStream; aString : String);
Var L : Integer;
Begin
 L := Length(aString);
 S.Write(L,4);
 S.Write(aString,L);
End;

Function TMainform.LoadStringFromStream(Const S : TFileStream) : String;
Var L : Integer;
    fStr : String;
Begin
 S.Read(L,4);
 S.Read(fStr,L);
 Result := fStr;
End;


ive done it before and that worked very well..
-- Write ----
1. Write Length of String
2. Write the string.
-- Read -----
1. Read length of string
2. Read String x length.

the resond is u use records with strings no length limit,
so i write/read record info manualy.
Comment
Watch Question

Commented:
Hi brainware,

this is my version:

function ReadStringFromStream(Stream: TStream): string;
var
  StrSize: Integer;
begin
  Stream.ReadBuffer(StrSize, SizeOf(Integer));
  SetLength(Result, StrSize);
  Stream.ReadBuffer(Pointer(Result)^, StrSize);
end;

function ReadStringFromStreamDelphiVersion(Stream: TStream): string;
var
  Reader: TReader;
begin
  Reader := TReader.Create(Stream, 1024);
  try
    Result := Reader.ReadString;
  finally
    Reader.Free;
  end;
end;

procedure WriteStringToStream(Stream: TStream; Value: string);
var
  StrSize: Integer;
begin
  StrSize:= Length(Value);
  Stream.WriteBuffer(StrSize, SizeOf(Integer));
  Stream.WriteBuffer(Pointer(Value)^, StrSize);
end;

procedure WriteStringToStreamDelphiVersion(Stream: TStream; Value: string);
var
  Writer: TWriter;
begin
  Writer := TWriter.Create(Stream, 1024);
  try
    Writer.WriteString(Value);
  finally
    Writer.Free;
  end;
end;


Best regards, Ivo.

Commented:
Hi brainware,

both of your functions are quite wrong:

Procedure TMainform.SaveStringToStream(Const S : TFileStream; aString : String);
Var L : Integer;
Begin
L := Length(aString);  // correct
S.Write(L,4);  // correct
S.Write(aString,L);  // error
End;

If you write the "aString" like this, you're not writing the characters, but instead the string pointer. You know, Delphi long strings are dynamic strings, which are internally realized by pointers (check "sizeOf(aString)", you'll get always 4, independent of the length of the string). You're writing the pointer to the characters to the file stream. You should use one of the following:

(1) if L > 0 then S.Write(aString[1],L);
(2) S.Write(pointer(aString)^, L);
(3) S.Write(pchar(aString)^, L);

Function TMainform.LoadStringFromStream(Const S : TFileStream) : String;
Var L : Integer;
   fStr : String;
Begin
S.Read(L,4);  // correct
S.Read(fStr,L);  // error
Result := fStr;
End;

In the erronous line "fStr" is just a pointer to an empty string. You're writing to a pointer variable, that's absolutely wrong. You have to do the same thing as in the first function, e.g. using "pchar(fStr)". Furthermore you have to make sure that the string buffer is big enough. So you have to call "SetLength(fStr,L)" before you call use "S.Read".

Regards, Madshi.

Commented:
P.S: In the last paragraph I meant "pchar(fStr)^", of course.

Commented:
Listening...

Commented:
You might also want to look at TStringStream, an example:

procedure TForm1.Button1Click(Sender: TObject);
var
   str : TStringStream;
begin
     str := TStringStream.create('');
     str.WriteString(memo1.text);//writing to a stream
     memo2.text := str.DataString;//reading from the stream
     str.free;
end;

Memo2 now has the same contents as Memo1.

GL
Mike

Commented:
madshi has explained very well why your code is not working well. Unfortunately he didn't provide a complete fixed version... here's the stuff:

Procedure SaveStringToStream(Const S : TFileStream; aString : String);
Var L : Integer;
Begin
     L := Length(aString);
     S.Write(L,4);
     S.Write(Pointer(aString)^,L);
End;

Function LoadStringFromStream(Const S : TFileStream) : String;
Var L : Integer;
Begin
     S.Read(L,4);
     SetLength(Result,L);
     S.Read(Pointer(Result)^,L);
End;

Do not accept this comment as answer, but rather madshi's.

Author

Commented:
Autch.. well Madshi's method works fine,
but am i wrong or aint the the same answers :/

ivobauer and madshi's answers that is..


 StrSize:= Length(Value);
 Stream.WriteBuffer(StrSize, SizeOf(Integer));
 Stream.WriteBuffer(Pointer(Value)^, StrSize);
-------------------------------------------------
 L := Length(aString);
 S.Write(L,4);
 S.Write(Pointer(aString)^,L);

correct me if im wrong..

Commented:
Yeah, you can give the points to Ivo, his answer his totally correct, of course. I only added my comment because Ivo didn't explain why your code was wrong.

Regards, Madshi.

Commented:
Hi brainware,

I'm sorry for posting my comment without explanation what was the wrong, because I was in a hurry... Neverthless Madshi did it (as expected) well! Decide by yourself whose comment is to be graded. I won't be afraid if you'll choose the madshi's one.

Best regards, Ivo.


Author

Commented:
Well ive been kind to Madshi many times before with stacks of Points :) so i think he can survive hhe..

Explore More ContentExplore courses, solutions, and other research materials related to this topic.