Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

record and TStream.write

0 views
Skip to first unread message

Jon Rowlan

unread,
May 19, 2002, 5:04:35 AM5/19/02
to
I have a TTreenode component on my form.

First time in, I build the tree list from a set of data tables, each record
has a unique record number (longint).

The record number is stored against the .data property.

Once built, I want to save my tree to a binary disk file so its quicker to
re-load later.

SaveTo and LoadFromFile does not work because it only stores the tree text,
not the .data property.

I have defined a record :

TreeRecord = record
Text: string;
r1: pointer;
end;

and have tried everything I can think of to write this to a TFileStream ..
this is the code that I thought should work ..

tr.Text := ANode.text;
tr.r1 := ANode.data;
Stream.Write(Pointer(tr)^, Length(tr));

but this gives me an "Invalid Typecast". Does anyone know of any good
examples of writing records to streams?

many thanks,

jON

Philip Jander

unread,
May 19, 2002, 6:07:00 AM5/19/02
to
Hi Jon,

> TreeRecord = record
> Text: string;
> r1: pointer;
> end;

assuming var tr:TreeRecord here.


> tr.Text := ANode.text;
> tr.r1 := ANode.data;
> Stream.Write(Pointer(tr)^, Length(tr));

storing a record (btw: generally you should used a packed record if you
directly access the memory)
would work (in principle) with :
Stream.Write(tr, SizeOf(tr));

However, there is a major pitfall here: if you execute your code, you
will only write the pointer to the string into the file, not the string
itself!
I would suggest storing the data into the stream using a TWriter object
(see help on TWriter+TReader). Create the TWriter right after creating
the TFileStream and use
myWriter.WriteString(ANode.text); {don't confuse this with
myWriter.WriteStr!}
myWriter.WriteInteger(LongInt(ANode.data));

Cheers,
Phil

Grinder

unread,
May 19, 2002, 4:29:29 PM5/19/02
to

"Jon Rowlan" <jon.r...@sads.com> wrote in message news:3ce76b10_2@dnews...

One quick note to start, if you're going to stream records, it's probably a
good idea to use packed records. The alignment of bytes withing a record is
optimized, and any system (including subsequent releases of Delphi) will
have to account for those alignments. Packed records will not include any
of this padding.

__________________

You can output a record, with something like:

Stream.Write(tr, sizeof(tr));

Unfortunately, you'll find that your record is probably only 8-bytes wide --
the Text member, when streamed, will put out a pointer to the data. You
might be able to fix this by declaring Text as a ShortString. This will
always output 256 bytes -- 1 byte for the string size, and 255 possible
bytes of data.

If your strings can exceed 255 characters, you'll have to resort to
something like:

Stream.Write(Cardinal(Length(tr.Text)), sizeof(Cardinal));
if Length(tr.Text) > 0 then
Stream.Write(tr.Text[1], Length(tr.Text));

and when you read it back in:

Stream.Read(iSize, sizeof(Cardinal));
SetLength(tr.Text, iSize);
if iSize > 0 then
Stream.Read(tr.Text[1], iSize);

This makes the use of a record of debatable value.
__________________

As for the pointer, it appears that the "real" data is just a 4-byte
Integer. String problems aside, your record would make more sense like:

> TreeRecord = record
> Text: string;

r1: Integer;
> end;

So you would set this value (from a TTreeNode) like:

tr.r1 := Integer(oNode.Data);

Assuming you've originally set the data value somethine like:

oNode.Data := Pointer(SomeIntegerValue);

____________________

If you're going to write a SaveToStream/LoadFromStream replacement, you'll
need to cache more information that this, however, as the nodes have a set
of relationships that will have to be maintained.


Peter Below (TeamB)

unread,
May 19, 2002, 4:50:44 PM5/19/02
to
In article <3ce76b10_2@dnews>, Jon Rowlan wrote:
> I have a TTreenode component on my form.
> First time in, I build the tree list from a set of data tables, each record
> has a unique record number (longint).
> The record number is stored against the .data property.
> Once built, I want to save my tree to a binary disk file so its quicker to
> re-load later.
> SaveTo and LoadFromFile does not work because it only stores the tree text,
> not the .data property.
>
> I have defined a record :
>
> TreeRecord = record
> Text: string;
> r1: pointer;
> end;
>
> and have tried everything I can think of to write this to a TFileStream ..

Your problem is that this record contains pointers, two of them, in fact. You
have to keep in mind that AnsiString (= String) is a pointer type, too, so
your Text field has a size of 4 bytes and holds a pointer to the characters
of the string. Storing pointers is worse than useless, of course, you need to
store the characters.

Search the archives for SaveTreeviewToStream and LoadTreeviewFromStream, that
will turn up some routines you can take as starting point.

--
Peter Below (TeamB)
Use the newsgroup archives :
http://www.mers.com/searchsite.html
http://www.tamaracka.com/search.htm
http://groups.google.com
http://www.prolix.be


0 new messages