protobuf数据类型与delphi数据类型映射
<p>protobuf数据类型与delphi数据类型映射</p><p>首先说明一下,在许多文档里面也把“结构”叫做“model(模型)”,在本文,我们统一叫做“结构”。结构,在C系语言用关键字“struct”表示,在pascal语言用“record”表示,在protobuf用"message"表示。</p>
<p><strong>protocol buffers是什么?</strong></p>
<p>是一种结构数据序列化方法。<br>定义数据的结构 > 生成的源代码(.proto文件) -> 在数据流中&各种语言进行编写, 读取结构数据。</p>
<p>是google gRPC数据序列的核心部件。google gRPC是业界最流行的一种IDL(接口描述语言)。</p>
<p><strong>如何使用?</strong></p>
<ol>
<li><strong>定义.proto文件</strong>, 来定义你的数据结构;(消息格式文件)中定义 protocol buffer message 类型, 来指定你想如何对序列化信息进行结构化。 message 包含name-value对, 可嵌套。缺省默认就设置为 optional。</li>
</ol>
<p><strong>为什么要用.proto文件来定义结构?</strong></p>
<p>protocol buffers与具体开发语言无关,正因为与开发语言无关,所有的主流语言都支持它(中立的,大家都支持),用.proto文件定义的结构,开发语言都提供有工具来自动翻译为自己语言能识别的结构代码,</p>
<p>所以用.proto文件定义的结构的数据序列、还原,支持跨语言、跨平台。</p>
<p>反之,如果,我们向其他语言开发者提供PASCAL的RECORD结构文件,一个他们可能会看不懂,二个其他语言可能没有工具来自动翻译。</p>
<p>注:</p>
<p>message xxx {<br>// 字段规则:required -> 字段只能也必须出现 1 次<br>// 字段规则:optional -> 字段可出现 0 次或1次<br>// 字段规则:repeated -> 字段可出现任意多次(包括 0)<br>// 类型:int32、int64、sint32、sint64、string、32-bit ....<br>// 字段编号:0 ~ 536870911(除去 19000 到 19999 之间的数字)<br>字段规则 类型 名称 = 字段编号;<br>}</p>
<p>1) message 定义中的每个字段都有唯一编号。<br>2) 单个 .proto 文件中定义多种 message 类型<br>3) message内可嵌套message<br>4) .proto 文件添加注释,可以使用 C/C++ 语法风格的注释 // 和 /* ... */</p>
<p>RuKuDan.proto</p>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">//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; //操作员
}
</pre>
</div>
<p> </p>
<p>2.<strong>使用ProtoBufCodeGen工具进行翻译,生成pascal语言的代码</strong>。<br>我们在 .proto 文件中定义了数据结构,这些数据结构是面向开发者和业务程序的,并不面向存储和传输。<br>当需要把这些数据进行存储或传输时,就需要将.proto 文件中定义的数据结构翻译为符合所使用开发语言语法的代码。我们提供全自动翻译工具。<br><img src="https://img2022.cnblogs.com/blog/368779/202206/368779-20220622081003094-1511231215.png"></p>
<p>pbRuKuDanMessages.pas</p>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">{ Unit pbRuKuDanMessages.pas }
{ Generated from RuKuDan.proto }
{ Package RuKuDan }
unit pbRuKuDanMessages;
interface
uses Grijjy.ProtocolBuffers, SysUtils;
{ TRuKuDan1Record }
type
TRuKuDan1Record = record
DanHao : String;
CangKu : String;
GongYingShang : String;
ShiJian : Int64;
CaoZuoYuan : String;
BeiZhu : String;
end;
{ TRuKuDan2Record }
type
TRuKuDan2Record = record
DanHao : String;
HangHao : String;
ShangPing : String;
JiaGe : Double;
ShuLiang : Double;
JinE : Double;
end;
{ TDynArrayRuKuDan2Record }
type
TDynArrayRuKuDan2Record = array of TRuKuDan2Record;
{ TRuKuDan2sRecord }
type
TRuKuDan2sRecord = record
Rkds : TDynArrayRuKuDan2Record;
end;
{ TRuKuDanRecord }
type
TRuKuDanRecord = record
Rkd1 : TRuKuDan1Record;
Rkd2 : TRuKuDan2sRecord;
end;
{ TRkdChaXunRecord }
type
TRkdChaXunRecord = record
KsShiJian : Int64;
JzShiJian : Int64;
CaoZuoYuan : String;
end;
implementation
end.</pre>
</div>
<p> 3.delphi对pbRuKuDanMessages.pas定义的结构进行读、写。</p>
<p><strong> 基于结构的二进制protobuf数据序列</strong></p>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">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);
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.Goodsid := db.qry.FieldByName('goodsid').AsString;
sps.Goodss.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;
</pre>
</div>
<p><strong>基于结构的JSON数据序列</strong></p>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">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);
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 := 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;
</pre>
</div>
<p> 从上面的代码可以看出,基于结构,既可以用于二进制(PROTBUF)序列,也可以用于明文(JSON)序列。 使用DELPHI的泛型结构,编程非常方便。</p>
<p><strong> protobuf数据类型:</strong></p>
<p>double: 浮点数</p>
<p>float: 单精度浮点</p>
<p>int32: int类型,使用可变长编码,编码负数不够高效,如果有负数那么使用sint32</p>
<p>sint32: int类型,使用可变长编码, 有符号的整形,比通常的int32高效;</p>
<p>uint32: 无符号整数使用可变长编码方式;</p>
<p>int64 long long , 使用可变长编码方式。编码负数时不够高效——如果有负数,可以使用sint64;</p>
<p>sint64 long long 使用可变长编码方式。有符号的整型值。编码时比通常的int64高效;</p>
<p>uint64: 无符号整数使用可变长编码方式;</p>
<p>fixed32 : 总是4个字节。如果数值总是比总是比2^28大的话,这个类型会比uint32高效。</p>
<p>fixed64: 总是8个字节。如果数值总是比总是比2^56大的话,这个类型会比uint64高效。</p>
<p>sfixed32: 总是4个字节。</p>
<p>sfixed64: 总是8个字节。</p>
<p>bool:bool值</p>
<p>string: 一个字符串必须是UTF-8编码或者7-bit ASCII编码的文本。</p>
<p>bytes: 可能包含任意顺序的字节数据。类似java的ByteString以及 c++ string。</p>
<p><strong>关于TDateTime类型</strong></p>
<p>protobuf没有TDateTime类型,榔个办?</p>
<p>解决方法是用时间戳,使用int64</p>
<p>uses dateutils;</p>
<p>DateTimeToUnix(),将TDateTime转换为时间戳<br>UnixToDateTime(),将时间戳转换为TDateTime</p>
<p> </p>
</div>
<div id="MySignature" role="contentinfo">
<p>本文来自博客园,作者:{咏南中间件},转载请注明原文链接:https://www.cnblogs.com/hnxxcxg/p/16241068.html</p><br><br>
来源:https://www.cnblogs.com/hnxxcxg/p/16241068.html
頁:
[1]