Megan
Megan

Reputation: 23

Reading Buffers

I am trying to store multiple files into one filestream and then dump them. For that, while merging them, I use buffers like this:

SetLength(header, 10);
header := Bytesof(Inttohex(SizeofStream, 10));
mystream2.WriteBuffer(header, Length(header));
mystream2.CopyFrom(mystream1, SizeofStream);

Also, in some special cases, where I need to distinguish two specific files, I use:

SetLength(header, 20);
header:= Bytesof(Inttohex(BS2.Size, 10) + Inttohex(BS3.Size, 10));
mystream2.WriteBuffer(header, Length(header));
mystream2.CopyFrom(BS2, 0);
mystream2.CopyFrom(BS3, 0);

So that I can easily decode it by taking first 10 bytes for the first stream's size & next 10 for later ones.

While restoration, I need to store all those headers into a Stringlist so that I can easily process them one after another using a loop. I tried using this:

FEncoding := TEncoding.Default;
SetLength(Buffer, mystream1.size);
myStream1.ReadBuffer(Pointer(Buffer)^, Length(Buffer));
SL1.Clear;
SL1.SetText(PWideChar(FEncoding.GetString(Buffer)));

But it doesn't work or even if it does, it just adds a few of the first buffers, that too in a single line instead of separate line for each buffer in String list. Can ya please tell me how to do it?

Upvotes: 0

Views: 1132

Answers (1)

Rob Kennedy
Rob Kennedy

Reputation: 163287

Your WriteBuffer call doesn't work the way you think it does. Header is a TBytes, which is a dynamic array. That means that the header variable itself is just a pointer to the actual array data. WriteBuffer writes the value that you pass it, which in this case is the pointer to the array data. To write the array data to the buffer, you need to dereference the pointer:

mystream2.WriteBuffer(header[0], Length(header));

To read from the stream, you need to invert all the steps you performed when writing. First, prepare the header buffer:

SetLength(header, 10);

Next, read the header from the stream:

mystream1.ReadBuffer(header[0], Length(header));

Finally, read the file data:

BS1.CopyFrom(mystream1, StrToInt64('$' + TEncoding.Default.GetString(header)));

The above assumes that you know there's just one file. If you don't know in advance how many files your stream contains, then you need some way of encoding that, too. You could add a header field to the start, before the first size header. Or you could just repeat the above three steps (SetLength, ReadBuffer, CopyFrom) until you reach the end of the stream.

You might also investigate using existing serialization technology instead of attempting to invent your own. For example, the tar format is one popular way of representing a stream of many files.

Upvotes: 2

Related Questions