首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >为什么德尔菲TMemoryStream读取TBytes和数组的字节是不同的?

为什么德尔菲TMemoryStream读取TBytes和数组的字节是不同的?
EN

Stack Overflow用户
提问于 2018-04-17 06:36:48
回答 1查看 10K关注 0票数 1

我正在编写一个使用Delphi2010对字节序列进行Z85Encoding的过程。所以我写了一个函数:

代码语言:javascript
运行
复制
function Z85Encode(input, output: TStream): integer

并期望通过一个。接下来,我编写了一个重载函数。

代码语言:javascript
运行
复制
function Z85Encode(b: TBytes): string;

它将字节序列写入TBytesStream (与调用encode函数相同),然后将编码数据读入结果字符串。

问题是我发现TStream.Read的行为与文档非常不同,我无法理解它。你我可以用其他方式完成这个函数,但我不太明白为什么?我想知道德尔菲是如何实现TBytes类型的。

为了说明我的问题,我编写了以下测试过程:

代码语言:javascript
运行
复制
procedure Test;
var
  iStream: TMemoryStream;
  n: integer;
  a: TBytes;
  b: TBytes
  c: array [0..4] of Byte;
begin
  b := TEncoding.UTF8.GetBytes('abcdefghij');  // byte from 97 to 106
  iStream := TMemoryStream.Create;
  try
    iStream.Write(b, Length(b));
    iStream.Seek(0, soBeginning);
    n := iStream.Read(a, 5); // expect only 5 bytes read, but the whole array is back.
    ShowMessage(IntToStr(n));  // n is 5
    ShowMessage(IntToStr(Length(a)));  // length is 10!!
    iStream.Seek(0, soBeginning);
    n := iStream.Read(c, 5);   // c contains random number, not 97, 98, ...
    ShowMessage(IntToStr(n));  // n is 5
  finally
    iStream.Free;
  end;
end;

第一个问题,根据文档,读应该只读字节数。但是,如果传入一个TBytes变量,它读取整个字节数组,但返回读计数为5。我还想知道为什么我不需要首先为变量a分配内存。看起来,Stream.Read将为变量分配内存,这不是预期的。

第二个问题,什么时候TStream.Read(c, 5)carray [0..4] of bytec数组中的值是一些随机值,而不是979899100101

通过进一步测试,如果我将TStream.Write更改为

代码语言:javascript
运行
复制
for n := 0 to High(b) do begin
  iStream.Write(b[n], 1);
end;

然后Read(a, 5)将不会得到任何结果,Length(a)将得到访问冲突,而Read(c, 5)将得到正确的结果。

、Read、和写似乎都采用了一个开放类型的参数,并根据参数类型的不同表现出不同的行为。如果最终是读取或写入变量的字节值,则行为不同是可以理解的,但它似乎比从变量中确定字节内容要做得更多。然后,、Read、和写将使用相同的变量类型,而不是我所期望的。

EN

回答 1

Stack Overflow用户

发布于 2018-04-17 07:08:00

您不是在编写数组的内容。您正在写入数组的地址。动态数组是一个指针。指针的值就是你正在写的东西。

若要写入数组,必须执行以下操作

代码语言:javascript
运行
复制
iStream.Write(b[0], Length(b));

代码语言:javascript
运行
复制
iStream.Write(Pointer(b)^, Length(b));

我更喜欢后者,因为即使启用了范围检查,它也适用于长度为0的数组。

同样地,从数组中读取。请注意,首先分配读缓冲区是您的责任。那不是你干的。

代码语言:javascript
运行
复制
SetLength(a, 5);
iStream.Read(Pointer(a)^, Length(a));

最后,可能最好使用WriteBufferReadBuffer,因为它们结束了错误检查,检查请求的字节数是否实际传输。

票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/49871382

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档