Delphi 结构体序列化为二进制串

需求

有时候需要把结构体的数据变成二进制串。比如一堆数据最后需要从网络传输出去。当然,对应的需求就是从二进制串变回结构体。

实现

常见办法

比较常见的办法是直接把结构体内存数据复制到二进制串的变量所指向的内存位置。例子代码如下:

Delphi 复制代码
TMyRecord = packed record
    MyName: string[6];
    MySize: Integer;
  end;


var
  R, Ra: TMyRecord;
  B1: TBytes;
begin
  R.MyName := 'abcxyz';
  R.MySize := 343;

  SetLength(B1, SizeOf(R));
  Move(R, B1[0], SizeOf(R));

  //再变回来

  Move(B1[0], Ra, SizeOf(Ra));  
end;

Delphi 的一个比较著名的控件 Indy 就是这样干的。请看它的代码:

Delphi 复制代码
function RawToBytes(const AValue; const ASize: Integer): TIdBytes;
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
  SetLength(Result, ASize);
  if ASize > 0 then begin
    Move(AValue, Result[0], ASize);
  end;
end;


procedure BytesToRaw(const AValue: TIdBytes; var VBuffer; const ASize: Integer);
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
  Assert(Length(AValue) >= ASize);
  Move(AValue[0], VBuffer, ASize);
end;

就是有两个变量,分别有自己的内存空间,使用 Move 方法把数据复制过去。

但是,复制数据是需要消耗 CPU 资源的。如果需要复制的数据很多,就会影响程序执行效率。

那么,我们不复制数据,直接使用指针,如何?

使用指针

Delphi 是强类型语言,最好不要使用通用指针,而是使用类型指针。因此我们需要先定义一下数据类型。代码:

Delphi 复制代码
TMyRecord = packed record
    MyName: string[6];
    MySize: Integer;
  end;

  PMyRecord = ^TMyRecord;

  TMyArr = array[0..10] of Byte;
  PMyArr = ^TMyArr;

在上述的数据类型基础上,我写了一段测试代码,执行成功。

Delphi 复制代码
procedure TForm1.Button4Click(Sender: TObject);
var
  B, B1: TMyArr;
  R: TMyRecord;
  Rx: PMyRecord;
begin
  //这样直接操作指针是成功的!
  R.MyName := 'abcxyz';
  R.MySize := 222;


  B := TMyArr(R);
  Move(B[0], B1[0], SizeOf(R));

  Rx := PMyRecord(@(B1[0]));
  Log(Rx^.MyName);
  Log(Rx^.MySize.ToString);
end;

解释一下:

上述代码的 R 是一个结构体,B 是 Byte 数组。直接类型转换 R 为 B,实际上就是把 R 的指针地址给了 B;

后面的 Move 是为了验证把 B 的数据复制到 B1 里面,是否成功;

最后,Rx 是结构体指针,把 B1 的地址给 Rx,我们获得了结构体 Rx。因为 Rx 是指针,所以最后访问 Rx 的内容时,后面加上了那个 ^ 符号,这个是 Delphi 语法。

总结:

结构体和 Byte 数组之间,可以直接通过指针的方式做类型转换,不同的数据类型的变量,实际上都是指向同一个内存块。这样避免了数据复制,程序更少消耗 CPU。

相关推荐
pcplayer4 天前
Delphi程序和大模型交互之二
人工智能·ai·大模型·agent·delphi
xyzhan13 天前
RAD Studio Amalthea Delphi 13.1 Beta深度解析:Delphi重磅更新,原生支持Windows ARM64EC
windows·delphi·rad studio·c++ builder·delphi 13
delphi 三层源码框架1 个月前
delphi发送SSL 465端口邮件
ssl·delphi·发送邮件·indy 465端口
tanqth4 个月前
Delphi跨平台开发中为Linux开发的优劣分析
跨平台·delphi·分析·linux开发
BillKu6 个月前
在 Delphi 5 中获取 Word 文档页数的方法
word·delphi
BillKu6 个月前
Delphi 5 中操作 Word 表格时禁用鼠标交互
word·delphi
看那山瞧那水6 个月前
DELPHI 利用OpenSSL实现加解密,证书(X.509)等功能
delphi·openssl
lincats6 个月前
一步一步学习使用FireMonkey动画(6) 用实例理解动画的运行状态
ide·delphi·livebindings·delphi 12.3·firemonkey
lincats6 个月前
一步一步学习使用FireMonkey动画(3) 使用Delphi的基本动画组件类
ide·delphi·delphi 12.3·firemonkey