Board index » delphi » How to save/load TSTRINGS to/from file???

How to save/load TSTRINGS to/from file???

I wrote a program that uses an array, consisting
of various variables (record). One of them is a 'TStrings'.

If I save the array to file and load it after that,
everything but the TStrings-var is restored.

Why?????

the program looks like this:

//----------------------------------------------------------------------

const
    max_x = 20;    max_y = 20;

type
    TElement = record
     a,b,c:integer;
     name:string[20];
     misc:TStrings;
    end;

    TMap = array[-max_x..max_x,-max_y..max_y]of TElement;

var
    map:TMap;

//----------------------------------------------------------------------

procedure TForm1.savetofile1Click(Sender: TObject);
var
   savefile:file of TMap;
begin
 repeat savedialog1.execute until savedialog1.filename<>'';
 assignfile(savefile, savedialog1.filename);
 rewrite(savefile);
 write(savefile, map);
 closefile(savefile);
end;

//----------------------------------------------------------------------

procedure TForm1.loadformfile1Click(Sender: TObject);
var
   savefile:file of TMap;
begin
 repeat opendialog1.execute until opendialog1.filename<>'';
 assignfile(savefile,opendialog1.filename);
 reset(savefile);
 read(savefile, map);
 closefile(savefile);
end;

//----------------------------------------------------------------------

thanks in advance
                        patrick

 

Re:How to save/load TSTRINGS to/from file???


Quote
patrick bergner wrote:
> I wrote a program that uses an array, consisting
> of various variables (record). One of them is a 'TStrings'.

> If I save the array to file and load it after that,
> everything but the TStrings-var is restored.

> Why?????

> the program looks like this:

> //----------------------------------------------------------------------

> const
>     max_x = 20;    max_y = 20;

> type
>     TElement = record
>      a,b,c:integer;
>      name:string[20];
>      misc:TStrings;
>     end;

>     TMap = array[-max_x..max_x,-max_y..max_y]of TElement;

> var
>     map:TMap;

> //----------------------------------------------------------------------

> procedure TForm1.savetofile1Click(Sender: TObject);
> var
>    savefile:file of TMap;
> [...]

    The TStrings is an object. That means it's "just a pointer". You're
saving the _value_ of the TStrings object. The value of the object
is the value of a certain pointer: you're saving the _address_
of your TStrings to the file. Reading back that address is useless,
there's not going to be a TStrings object at that same address when
you re-open the file.

    You need to store the actual strings in the file. A Delphi string
can contain anything, so in general if you want to write a string
to a file you need to write the length of the string first so you
know where to stop when you read it back. If your strings are
in a TStrings object they're just text (or they'd better be), which
simplifies things. You could first write a fixed-size integer saying
how many strings there are (so you know where one TMap ends
and the next one starts) and then write the strings one by one,
each string followed by a CRLF (#13#10) marking the end of the
string. Or a null or something.

    (Given that a TMap contains pointers you're not going to be able
to use a "file of TMap" - it's going to have to be an untyped file.)

Re:How to save/load TSTRINGS to/from file???


But if I save a single TStrings into a file, it works!!!!
(with the TStrings.SaveToFile() command!);

Is there no way of saving it with read/write???

I use a map of more than 400 fields and for every field
there is the chance to fill text in a richedit. Differned
lenghts etc.

The other method would be much easier!!! No idea?

Thanks in advance
                        patrick!!!

David C. Ullrich schrieb:

Quote

> patrick bergner wrote:

> > I wrote a program that uses an array, consisting
> > of various variables (record). One of them is a 'TStrings'.

> > If I save the array to file and load it after that,
> > everything but the TStrings-var is restored.

> > Why?????

> > the program looks like this:

> > //----------------------------------------------------------------------

> > const
> >     max_x = 20;    max_y = 20;

> > type
> >     TElement = record
> >      a,b,c:integer;
> >      name:string[20];
> >      misc:TStrings;
> >     end;

> >     TMap = array[-max_x..max_x,-max_y..max_y]of TElement;

> > var
> >     map:TMap;

> > //----------------------------------------------------------------------

> > procedure TForm1.savetofile1Click(Sender: TObject);
> > var
> >    savefile:file of TMap;
> > [...]

>     The TStrings is an object. That means it's "just a pointer". You're
> saving the _value_ of the TStrings object. The value of the object
> is the value of a certain pointer: you're saving the _address_
> of your TStrings to the file. Reading back that address is useless,
> there's not going to be a TStrings object at that same address when
> you re-open the file.

>     You need to store the actual strings in the file. A Delphi string
> can contain anything, so in general if you want to write a string
> to a file you need to write the length of the string first so you
> know where to stop when you read it back. If your strings are
> in a TStrings object they're just text (or they'd better be), which
> simplifies things. You could first write a fixed-size integer saying
> how many strings there are (so you know where one TMap ends
> and the next one starts) and then write the strings one by one,
> each string followed by a CRLF (#13#10) marking the end of the
> string. Or a null or something.

>     (Given that a TMap contains pointers you're not going to be able
> to use a "file of TMap" - it's going to have to be an untyped file.)

Re:How to save/load TSTRINGS to/from file???


Quote
patrick bergner wrote:
> But if I save a single TStrings into a file, it works!!!!
> (with the TStrings.SaveToFile() command!);

> Is there no way of saving it with read/write???

    Yes. For example you could do what I suggested.
There's no way of saving it with just one Write.

    Hmm, I suppose you could save the data in each TStrings
by writing the Text property. But you're still going to need
to first record the length, and you're going to need to do
that once for each string.

Quote
> I use a map of more than 400 fields and for every field
> there is the chance to fill text in a richedit. Differned
> lenghts etc.

> The other method would be much easier!!! No idea?

> Thanks in advance
>                         patrick!!!

Re:How to save/load TSTRINGS to/from file???


In article <37A61DFC.2086E...@t-online.de>, patrick bergner

Quote
<patrick.berg...@t-online.de> writes:
>I wrote a program that uses an array, consisting
>of various variables (record). One of them is a 'TStrings'.

>If I save the array to file and load it after that,
>everything but the TStrings-var is restored.

You might be better using streams as  :-

procedure WriteStreamStrList(Stream : TStream; SL : TStringList);
var
  i : integer;
begin
  with SL do begin
    WriteStreamInt(Stream, Count);
    for i := 0 to Count - 1 do begin
      WriteStreamInteger(Stream, Length(Strings[i]));
      WriteStreamStr(Stream, Strings[i];
    end;
  end;
end;

procedure ReadStreamStrList(Stream : TStream; SL : TSrtingList);
var
  i : integer;
begin
  with SL do
    for i := 0 to ReadStreamInt(Stream) - 1 do begin
      SL.Add(ReadStreamStr(Stream));
end;

procedure WriteStreamInt(Stream : TStream; Num : integer);
{writes an integer to the stream}
begin
  Stream.Write(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);
  {write characters}
  Stream.Write(Str[1], StrLen);
end;

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

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

The ReadStreamStrList and WriteStreamStrList I have not tested, the others work
OK.

Alan Lloyd
alangll...@aol.com

Other Threads