With TStringStream, the bytes
using its Bytes
property differs from the bytes
extracted using TStream.Read
. As shown below:
- the
bytes
extracted usingTStream.Read
represents correct data. - the
bytes
using itsBytes
property contains more data.(the last byte of correctbytes
is different from that of wrongbytes
)
Could you help to comment about the possible reason? Thank you very much for your help!
PS: Delphi XE, Windows 7. (It seems TStringStream back in Delphi 7 doesn't have LoadFromFile or SaveToFile.)
PS: The sample files can be download from SkyDrive: REF_EncodedSample & REF_DecodedSample. (Zlib-compressed image file.).
procedure CompareBytes_2;
var
ss_1: TStringStream;
ss_2: TStringStream;
sbytes_Read: TBytes;
sbytes_Property: TBytes;
len_sbytes_Read: Integer;
len_sbytes_Property: Integer;
filename: string;
begin
filename := 'REF_EncodedSample'; // textual data
// filename := 'REF_DecodedSample'; // non-textual data
ss_1 := TStringStream.Create;
ss_1.LoadFromFile(filename);
ss_2 := TStringStream.Create;
ss_2.LoadFromFile(filename);
ss_1.SaveToFile(filename+ '_CopyByStringStream_1');
ss_2.SaveToFile(filename+ '_CopyByStringStream_2');
len_sbytes_Read := ss_1.Size;
SetLength(sbytes_Read, len_sbytes_Read);
ss_1.Read(sbytes_Read[0], len_sbytes_Read);
sbytes_Property := ss_2.Bytes;
ShowMessage(
BoolToStr(
Length(sbytes_Read) = Length(sbytes_Property),
True));
ShowMessage(
BoolToStr(
sbytes_Read[len_sbytes_Read - 1] = sbytes_Property[len_sbytes_Read - 1],
True));
ss_1.Free;
ss_2.Free;
end;
The string stream documentation states:
Presumably the buffer has been allocated to hold more space than it actually needs. Only the first Size bytes of the buffer contain valid content.
Also, the call to ss_1.Read is a little pointless since Length(sbytes_Read) does not change after the call to SetLength. And when reading from a stream you are to use ReadBuffer rather than Read. Likewise for WriteBuffer.
It is impossible for
Read()
to return different bytes than what is in theBytes
property, asRead()
reads from the sameTBytes
object in memory that theBytes
property uses.In D2009+,
TStringStream
was changed to derive from TBytesStream, which in turn derives fromTMemoryStream
. That is whyTStringStream
hasLoadFromFile()
andSaveToFile()
methods available now. In earlier versions,TStringStream
derived directly fromTStream
instead.TStringStream
now stores encoded bytes, not aString
like it did in earlier versions. TheTStringStream
contructor takes aString
as input and encodes it to aTBytes
using the specifiedTEncoding
(whereTEncoding.Default
is used if you do not specify aTEncoding
). TheDataString
property getter decodes that sameTBytes
back to aString
using theTEncoding
that was specified in the constructor. TheLoadFromFile()
andSaveToFile()
methods load/save theTBytes
as-is without any encoding/decoding performed at all.So, if you call
LoadFromFile()
, it will store the file data as-is in the stream. If the encoding of that data does not match theTEncoding
that is passed to the constructor, theDataStream
property is going to return garbage, but theBytes
property and theRead()
method will work just fine.Your problem is you are not taking into account that the
Bytes
property returns the entire memory block thatTMemoryStream
allocates for its data storage.TMemoryStream
allocates memory in chunks based on deltas, so it is possible for it to allocate more memory than it actually needs, that is why it has separateCapacity
andSize
properties. TheCapacity
property indicates the total size of the allocated memory, whereas theSize
property indicates how many bytes have been stored in the allocated memory. When you callLoadFromFile()
, theBytes
property will almost always be larger than the size of the file that was loaded.So basically, your code is comparing the proverbial "apples" to "oranges", which is why you are getting bad results. You need to fix your code accordingly, to account for the difference between the
Capacity
andSize
properties. The contents of the twoTBytes
variables will be identical up toSize
bytes. You are comparing more than that, which is why your code is failing.