protobuf数据类型与delphi数据类型映射
protobuf数据类型与delphi数据类型映射
首先说明一下,在许多文档里面也把“结构”叫做“model(模型)”,在本文,我们统一叫做“结构”。结构,在C系语言用关键字“struct”表示,在pascal语言用“record”表示,在protobuf用"message"表示。
protocol buffers是什么?
是一种结构数据序列化方法。
定义数据的结构 > 生成的源代码(.proto文件) -> 在数据流中&各种语言进行编写, 读取结构数据。
是google gRPC数据序列的核心部件。google gRPC是业界最流行的一种IDL(接口描述语言)。
如何使用?
- 定义.proto文件, 来定义你的数据结构;(消息格式文件)中定义 protocol buffer message 类型, 来指定你想如何对序列化信息进行结构化。 message 包含name-value对, 可嵌套。缺省默认就设置为 optional。
为什么要用.proto文件来定义结构?
protocol buffers与具体开发语言无关,正因为与开发语言无关,所有的主流语言都支持它(中立的,大家都支持),用.proto文件定义的结构,开发语言都提供有工具来自动翻译为自己语言能识别的结构代码,
所以用.proto文件定义的结构的数据序列、还原,支持跨语言、跨平台。
反之,如果,我们向其他语言开发者提供PASCAL的RECORD结构文件,一个他们可能会看不懂,二个其他语言可能没有工具来自动翻译。
注:
message xxx {
// 字段规则:required -> 字段只能也必须出现 1 次
// 字段规则:optional -> 字段可出现 0 次或1次
// 字段规则:repeated -> 字段可出现任意多次(包括 0)
// 类型:int32、int64、sint32、sint64、string、32-bit ....
// 字段编号:0 ~ 536870911(除去 19000 到 19999 之间的数字)
字段规则 类型 名称 = 字段编号;
}
1) message 定义中的每个字段都有唯一编号。
2) 单个 .proto 文件中定义多种 message 类型
3) message内可嵌套message
4) .proto 文件添加注释,可以使用 C/C++ 语法风格的注释 // 和 /* ... */
RuKuDan.proto
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | //protobuf模板文件 syntax= "proto3" ; package RuKuDan; //入库单 主表 message RuKuDan1 { string DanHao = 1; //单号 string CangKu = 2; //仓库 string GongYingShang = 3; //供应商 int64 ShiJian = 4; //时间 string CaoZuoYuan = 5; //操作员 string BeiZhu = 6; //备注 } //入库单 明细 message RuKuDan2 { string DanHao = 1; //单号 string HangHao = 2; //行号 string ShangPing = 3; //商品 double JiaGe = 4; //价格 double ShuLiang = 5; //数量 double JinE = 6; //金额 } //入库单 明细数组 message RuKuDan2s { repeated RuKuDan2 rkds = 1; } //入库单 message RuKuDan { RuKuDan1 rkd1 = 1; RuKuDan2s rkd2 = 2; } //查询条件 message rkdChaXun { int64 ksShiJian = 1; //开始时间 int64 jzShiJian = 2; //截止时间 string CaoZuoYuan = 3; //操作员 } |
2.使用ProtoBufCodeGen工具进行翻译,生成pascal语言的代码。
我们在 .proto 文件中定义了数据结构,这些数据结构是面向开发者和业务程序的,并不面向存储和传输。
当需要把这些数据进行存储或传输时,就需要将.proto 文件中定义的数据结构翻译为符合所使用开发语言语法的代码。我们提供全自动翻译工具。
pbRuKuDanMessages.pas
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 | { Unit pbRuKuDanMessages.pas } { Generated from RuKuDan.proto } { Package RuKuDan } unit pbRuKuDanMessages; interface uses Grijjy.ProtocolBuffers, SysUtils; { TRuKuDan1Record } type TRuKuDan1Record = record [Serialize(1)] DanHao : String; [Serialize(2)] CangKu : String; [Serialize(3)] GongYingShang : String; [Serialize(4)] ShiJian : Int64; [Serialize(5)] CaoZuoYuan : String; [Serialize(6)] BeiZhu : String; end; { TRuKuDan2Record } type TRuKuDan2Record = record [Serialize(1)] DanHao : String; [Serialize(2)] HangHao : String; [Serialize(3)] ShangPing : String; [Serialize(4)] JiaGe : Double; [Serialize(5)] ShuLiang : Double; [Serialize(6)] JinE : Double; end; { TDynArrayRuKuDan2Record } type TDynArrayRuKuDan2Record = array of TRuKuDan2Record; { TRuKuDan2sRecord } type TRuKuDan2sRecord = record [Serialize(1)] Rkds : TDynArrayRuKuDan2Record; end; { TRuKuDanRecord } type TRuKuDanRecord = record [Serialize(1)] Rkd1 : TRuKuDan1Record; [Serialize(2)] Rkd2 : TRuKuDan2sRecord; end; { TRkdChaXunRecord } type TRkdChaXunRecord = record [Serialize(1)] KsShiJian : Int64; [Serialize(2)] JzShiJian : Int64; [Serialize(3)] CaoZuoYuan : String; end; implementation end. |
3.delphi对pbRuKuDanMessages.pas定义的结构进行读、写。
基于结构的二进制protobuf数据序列
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | function goodsQry(url: string ; body: tbytes): tbytes; var db: tdb; pool: tdbpool; serial: TgoProtocolBuffer; arr: tarray< string >; dw: TUnitsRecord; sp: TGoodsRecord; sps: pbGoodsMessages.TGoodsArrRecord; i: integer; err: TresRecord; begin serial := TgoProtocolBuffer.Create; try try arr := url.Split([ '/' ]); pool := GetDBPool(arr[4]); db := pool.Lock; db.qry.Close; db.qry.SQL.Clear; db.qry.SQL.Text := 'select * from tgoods' ; db.qry.Open; SetLength(sps.Goodss, db.qry.RecordCount); db.qry.First; i := 0; while not db.qry.Eof do begin sps.Goodss[i].Goodsid := db.qry.FieldByName( 'goodsid' ).AsString; sps.Goodss[i].Goodsname := db.qry.FieldByName( 'goodsname' ).AsString; inc(i); db.qry.Next; end; Result := serial.Serialize<pbGoodsMessages.TGoodsArrRecord>(sps); except on E: Exception do begin err.ok := False; err.err := e.Message; Result := serial.Serialize<TresRecord>(err); end; end; finally pool.Unlock(db); serial.Free; end; end; |
基于结构的JSON数据序列
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | function goodsQry(url: string ; body: rawbytestring): string ; var db: tdb; pool: tdbpool; arr: tarray< string >; serial: TJsonSerializer; sp: TGoodsrecord; sps: TGoodsArrRecord; i: Integer; err: TResRecord; begin serial := TJsonSerializer.Create; try try arr := url.Split([ '/' ]); pool := GetDBPool(arr[4]); db := pool.Lock; db.qry.Close; db.qry.SQL.Clear; db.qry.SQL.Text := 'select * from tgoods' ; db.qry.Open; SetLength(sps.Goodss, db.qry.RecordCount); db.qry.First; i := 0; while not db.qry.Eof do begin sp.goodsid := db.qry.FieldByName( 'goodsid' ).AsString; sp.goodsname := db.qry.FieldByName( 'goodsname' ).AsString; sps.Goodss[i] := sp; inc(i); db.qry.Next; end; Result := serial.Serialize<TGoodsArrRecord>(sps); except on E: Exception do begin err.ok := False; err.err := e.Message; Result := serial.Serialize<TResRecord>(err); end; end; finally pool.Unlock(db); serial.Free; end; end; |
从上面的代码可以看出,基于结构,既可以用于二进制(PROTBUF)序列,也可以用于明文(JSON)序列。 使用DELPHI的泛型结构,编程非常方便。
protobuf数据类型:
double: 浮点数
float: 单精度浮点
int32: int类型,使用可变长编码,编码负数不够高效,如果有负数那么使用sint32
sint32: int类型,使用可变长编码, 有符号的整形,比通常的int32高效;
uint32: 无符号整数使用可变长编码方式;
int64 long long , 使用可变长编码方式。编码负数时不够高效——如果有负数,可以使用sint64;
sint64 long long 使用可变长编码方式。有符号的整型值。编码时比通常的int64高效;
uint64: 无符号整数使用可变长编码方式;
fixed32 : 总是4个字节。如果数值总是比总是比2^28大的话,这个类型会比uint32高效。
fixed64: 总是8个字节。如果数值总是比总是比2^56大的话,这个类型会比uint64高效。
sfixed32: 总是4个字节。
sfixed64: 总是8个字节。
bool:bool值
string: 一个字符串必须是UTF-8编码或者7-bit ASCII编码的文本。
bytes: 可能包含任意顺序的字节数据。类似java的ByteString以及 c++ string。
关于TDateTime类型
protobuf没有TDateTime类型,榔个办?
解决方法是用时间戳,使用int64
uses dateutils;
DateTimeToUnix(),将TDateTime转换为时间戳
UnixToDateTime(),将时间戳转换为TDateTime
本文来自博客园,作者:{咏南中间件},转载请注明原文链接:https://www.cnblogs.com/hnxxcxg/p/16241068.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
2012-05-07 界面演示