为什么TStringStream.Bytes与'TStream.Read'的不同之处

时间:2012-07-05 21:50:03

标签: delphi byte stringstream

使用TStringStream时,使用bytes属性的Bytes与使用bytes提取的TStream.Read不同。如下图所示:

  1. 使用bytes提取的TStream.Read表示正确的数据。
  2. bytes使用其Bytes属性包含更多数据。 (正确的bytes的最后一个字节与错误的bytes的最后一个字节不同
  3. 你能帮忙评论可能的原因吗?非常感谢你的帮助!

    PS:Delphi XE,Windows 7.(似乎在Delphi 7中的TStringStream没有LoadFromFile或SaveToFile。)

    PS:可以从SkyDrive下载示例文件:REF_EncodedSample & REF_DecodedSample。 (Zlib压缩的图像文件。)。

    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;
    

2 个答案:

答案 0 :(得分:5)

字符串流documentation表示:

  

Bytes属性返回存储数据的缓冲区。使用Size属性查找缓冲区中的实际数据量。

据推测,缓冲区已被分配用于容纳比实际需要更多的空间。只有缓冲区的第一个Size字节包含有效内容。


此外,对ss_1.Read的调用有点无意义,因为在调用SetLength之后Length(sbytes_Read)没有改变。从流中读取时,您将使用ReadBuffer而不是Read。同样适用于WriteBuffer。

答案 1 :(得分:4)

Read()不可能返回与Bytes属性不同的字节,因为Read()从内存中的TBytes对象读取Bytes TStringStream 1}}属性使用。

在D2009 +中,TMemoryStream被更改为从TBytesStream派生,而TBytesStream又派生自TStringStream。这就是为什么LoadFromFile()现在有SaveToFile()TStringStream方法可用的原因。在早期版本中,TStream直接来自TStringStreamString现在存储编码的字节,而不像早期版本中那样存储TStringStreamString构造函数将TBytes作为输入,并使用指定的TEncoding将其编码为TEncoding.Default(如果您未指定{TEncoding,则使用DataString {1}})。 TBytes属性getter使用构造函数中指定的String将相同的TEncoding解码回LoadFromFile()SaveToFile()TBytes方法按原样加载/保存LoadFromFile(),而根本不执行任何编码/解码。

因此,如果您调用TEncoding,它将按原样将文件数据存储在流中。如果该数据的编码与传递给构造函数的DataStream不匹配,则Bytes属性将返回垃圾,但Read()属性和Bytes方法会很好。

您的问题是您没有考虑TMemoryStream属性返回TMemoryStream为其数据存储分配的整个内存块。 Capacity基于增量分配内存,因此它可以分配比实际需要更多的内存,这就是它具有单独的SizeCapacity属性的原因。 Size属性指示已分配内存的总大小,而LoadFromFile()属性指示已分配内存中已存储的字节数。当您调用Bytes时,Capacity属性几乎总是大于已加载文件的大小。

所以基本上,你的代码将众所周知的“苹果”与“橙子”进行比较,这就是为什么你会得到不好的结果。您需要相应地修改代码,以便考虑SizeTBytes属性之间的差异。两个Size变量的内容将相同最多{{1}}个字节。您正在比较更多,这就是您的代码失败的原因。