【问题标题】:What is the purpose of the Count parameter of TStream.WriteData and TStream.ReadData?TStream.WriteData和TStream.ReadData的Count参数的作用是什么?
【发布时间】:2014-11-26 13:45:41
【问题描述】:

TStream 类包含许多采用这种形式的 WriteData 重载:

function WriteData(const Buffer: Int32; Count: Longint): Longint; overload;

所有常见的嫌疑犯都有重载,AnsiCharCharUInt32Double 等等。 ReadData 也是如此。我试图了解 Count 参数的用途。上面提到的重载的实现如下:

function TStream.Skip(Amount: Integer): Integer;
var
  P: Integer;
begin
  P := Position;
  Result := Seek(Amount, soCurrent) - P;
end;

function TStream.WriteData(const Buffer: Int32; Count: Longint): Longint;
const
  BufSize = SizeOf(Buffer);
begin
  if Count > BufSize then
    Result := Write(Buffer, BufSize) + Skip(Count - BufSize)
  else
    Result := Write(Buffer, Count)
end;

我可以清楚地看到这段代码做了什么,但我不明白为什么执行部分写入是有意义的。为什么用Count < BufSize 调用这个函数有意义?这种行为非常奇怪。

有谁知道为什么要添加这些重载以及它们的目的是什么?当然我看过documentation 对这些方法没什么好说的。


顺便说一句,我将提交有关此行的错误报告:

Result := Write(Buffer, BufSize) + Skip(Count - BufSize);

假设调用Write 将发生在调用Skip 之前是错误的。 + 运算符的操作数的计算顺序未定义。这段代码应该这样写:

Result := Write(Buffer, BufSize);
inc(Result, Skip(Count - BufSize));

【问题讨论】:

  • 你从不想写半个 Unicode 字符 :) ?
  • @TLama 至少在小端机器上它会是右半边!
  • 在快速搜索 Delphi XE3 附带的源代码后,我发现只有 TclientDataset 组件在将数据写入流时使用带有附加大小参数的 WriteData。为什么它以这种方式使用它?我不知道。或许您在查看 TClientDataset 代码后,会自己对此有更好的理解。
  • 当我有一个特定大小的动态数组时,我实际上做了很多次,但我只想将它的一部分写入文件,例如如果我在一个数组中有一个已过滤的信号,该数组具有进出数据缓冲区,并且我只想写入真实数据(没有开销),我经常引用完整的动态数组(或任何其他指向缓冲区的指针)并提供实际写入数据的计数。
  • @mrabat 这不是这里发生的事情。这里的代码能够写入部分值。所以,只有 3 个字节的整数,或者更糟糕的是,

标签: delphi delphi-xe7


【解决方案1】:

理论构建

if TStream 早于 overload 关键字(Delphi 3 IIRC)的引入,他们可能引入了一种写入整数的方法,可能是 int32。当使用“字节”变量调用函数时,它将作为整数传递给函数,然后 Count 参数将只允许写入单个字节。现在他们支持这个是为了向后兼容。

在某些情况下(比如下一个),支持Count < Bufsize 确实特别傻:

function WriteData(const Buffer: Int8; Count: Longint): Longint; overload;

另一个理由是在下一种情况下,变量只需要作为 Int8 保存到流中,但在程序执行期间作为 Int32 处理(因为它被传递给只接受 var : Int32 的函数参数)。

procedure SomeProc(var MyInt : Integer);

procedure DoSomeStream;
var
  iVal : Integer;
//  bVal : ShortInt;
begin
  SomeProc(iVal);
  Stream.WriteData(iVal, SizeOf(Byte));
  //Instead of
//  SomeProc(iVal);
//  bVal := iVal;
//  Stream.WriteData(bVal)
end;

我并不是说它是必需的(可以解决),但在某些极端情况下,它可能很有用。

【讨论】:

  • > ".. 向后兼容性.." > .ReadData .WriteData 是在 XE3 中的“重载”之后引入的。
  • TStream 在下一代编译器开始出现之前非常稳定,然后一切都开始了。所以我不认为是这样。
  • @DavidHeffernan 是的,已经引入了一些奇怪和损坏的代码,所以很难说为什么会有这个代码。
【解决方案2】:

对我来说,这段代码似乎可以让您写入一些数据,而不是跳到数据后面很远的位置。

例如你有一个包含多个整数的流,并且你想每 5 次覆盖一次,你可以这样做:

mData := 15;
WriteData(mData, SizeOf(mData) * 5);

【讨论】:

  • 这是我理解的部分。为什么执行部分写入有意义?在我写的问题中:“为什么用 Count
猜你喜欢
  • 2010-09-22
  • 2021-12-22
  • 1970-01-01
  • 2015-07-13
  • 2020-02-18
  • 2020-11-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多