delphi - 为什么Delphi TMemoryStream读取的TBytes和字节数组不同?

标签 delphi delphi-2010

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

function Z85Encode(input, output: TStream): integer


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

function Z85Encode(b: TBytes): string;


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

问题是我发现TStream.Read的行为与文档非常不同,我无法理解。您可以使用其他方式完成功能,但是我不太明白为什么吗?我可能想知道Delphi如何实现TBytes类型。

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

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;


第一个问题,根据文件,Read应该只读取字节数。但是,如果我传入一个TBytes变量,它将读取整个字节数组,但返回读取计数为5。我也想知道为什么我不需要首先为变量'a'分配内存。似乎Stream.Read会为该变量分配内存,这是意外的。

第二个问题,当TStream.Read(c,5)时c是字节数组[0..4]。 c数组中的值是一些随机值,而不是97、98、99、100和101。

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

for n := 0 to High(b) do begin
  iStream.Write(b[n], 1);
end;


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

似乎“读取”和“写入”都采用开放类型的参数,并且根据参数类型的不同而表现不同。如果最终将要读取或写入变量的字节值,则行为不同是可以理解的,但是似乎要做更多的工作就是从变量中确定字节内容。然后,读取和写入将使用相同的变量类型,这不是我的期望。

最佳答案

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

要编写数组,您必须做

iStream.Write(b[0], Length(b));


要么

iStream.Write(Pointer(b)^, Length(b));


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

同样从数组中读取。请注意,您有责任首先分配读取缓冲区。你没那么做

SetLength(a, 5);
iStream.Read(Pointer(a)^, Length(a));


最后,使用WriteBufferReadBuffer可能更可取,因为它们会包装错误检查以确保实际传输了请求的字节数。

关于delphi - 为什么Delphi TMemoryStream读取的TBytes和字节数组不同?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49871382/

相关文章:

delphi - 如何获取访问该 Variant 的 Delphi 6 索引属性的基础原始 Variant 值?

delphi - 如何增加外部调试器可视化工具可以显示的字符串的大小?

windows - Wow64DisableWow64Fs重定向文件退出

delphi - 用delphi编写客户端-服务器应用程序

Delphi TreeView : Can I have different styles in one node's text?

multithreading - 在线程停止时关闭窗口

delphi - 创建和/或写入文件

delphi - 向用户显示累积的消息

android - 获取注册的电子邮件帐户

delphi - 在表单上放置 TMemo 后,TMainMenu 图标消失