protobuf数据处理
一、PROTOBUF 介绍
1.1 简介
Protobuf(Protocol Buffers)是 google 开发的一种数据描述语言,它能够将结构化的数据序列化,并且可以将序列化的数据进行反序列化恢复原有的数据结构。一般用于数据存储以及通信协议方面。
它类似于 JSON,但更小更快,并且可以生成原生语言绑定。您只需定义一次数据结构,然后可以使用特定生成的源代码,轻松地在各种数据流中以及使用各种语言读写结构化数据。
PROTOBUF 解决了哪些问题?
PROTOBUF 提供了一种适合用于几兆字节大小的类型化、结构化数据包的序列化格式。该格式适用于瞬时网络流量和长期数据存储。PROTOBUF 可以扩展新的信息,而不会使现有数据无效,也不需要更新代码。
具体细节可以参考官方文档:https://protobuf.dev/overview/
1.2 proto 编译为 pb 方法
1、根据电脑的操作系统去 https://repo1.maven.org/maven2/com/google/protobuf/protoc/2.6.1/去下载对应的 protobuf2 exe,如果是 windows-x86_64,直接使用本目录下的 protoc-2.6.1-windows-x86_64.exe 即可
2、把 proto 文件复制到本目录
3、打开 cmd,输入 protoc-2.6.1-windows-x86_64 --descriptor_set_out=tracker.pb tracker.proto 命令(注意修改 protoc exe、proto 和 pb 的文件名)就在同一级目录下生成了 proto 对应的 pb 文件
二、演示功能概述
本 demo 通过使用 Air8101 开发板,将 table 类型数据转为 PROTOBUF 格式,以及将 PROTOBUF 格式转为 table。
三、准备硬件环境
“古人云:‘工欲善其事,必先利其器。’在深入介绍本功能示例之前,我们首先需要确保以下硬件环境的准备工作已经完成。”
参考:硬件环境清单,准备以及组装好硬件环境。
四、软件环境
“凡事预则立,不预则废。”在详细阐述本功能示例之前,我们需先精心筹备好以下软件环境。
- Luatools 工具;
- 内核固件文件(底层 core 固件文件):LuatOS-SoC_V10001_Air8101.soc;参考项目使用的内核固件;
- luatos 需要的脚本和资源文件
脚本和资源文件:https://gitee.com/openLuat/LuatOS-Air8101/tree/master/demo/wlan/softAP
lib 脚本文件:使用 Luatools 烧录时,勾选 添加默认 lib 选项,使用默认 lib 脚本文件;
准备好软件环境之后,接下来查看如何烧录项目文件到 Air8101 开发板,将本篇文章中演示使用的项目文件烧录到 Air8101 开发板中。
五、API 介绍
5.1 protobuf.load(pbdata)
作用:加载 pb 二进制定义数据。
参数:
**参数** | **传入值类型** | **解释** |
pbdata | string | 通过protoc.exe程序转换得到的数据,通常从文件读取得到 |
返回值:
**返回值类型** | **解释** |
bool | 成功与否 |
int | 读取了多长, 调试用 |
5.2 protobuf.encode(tpname, data)
作用:编码 protobuffs 数据包。
参数:
**参数** | **传入值类型** | **解释** |
tpname | string | 数据类型名称, 定义在pb文件中, 由protobuf.load加载 |
data | table | 待编码数据, 必须是table, 内容符合pb文件里的定义 |
返回值:
**返回值类型** | **解释** |
string | 编码后的数据,若失败会返回nil |
5.3 protobuf.decode(tpname, data)
作用:解码 protobuffs 数据包。
参数:
**参数** | **传入值类型** | **解释** |
tpname | string | 数据类型名称, 定义在pb文件中, 由protobuf.load加载 |
data | string | 待编码数据 |
返回值:
**返回值类型** | **解释** |
table | 解码后的数据 |
六、代码示例介绍
6.1 DEMO 主要组件的详细解释:
6.1.1PROJECT 和 VERSION
这两行代码用于设置项目的名称和版本:
PROJECT = "protobuf_demo"
VERSION = "1.0.0"
6.1.2 PB 文件加载
代码检查是否存在文件 /luadb/person.pb
,如果存在,就会加载该文件并发布事件 pb_file_exists
,这意味着 PROTOBUF 定义文件已成功加载:
local pb_file = "/luadb/person.pb"
if io.exists(pb_file) then
protobuf.load(io.readFile(pb_file))
sys.publish("pb_file_exists")
else
log.info("protobuf","Failed to load file")
end
6.1.3 数据编码
一旦加载了 PROTOBUF 文件,代码会创建一个 Lua 表 tb
,并将其编码为 PROTOBUF 数据。之后,它还会使用 JSON 对数据进行编码并打印出来进行对比:
local tb = {
name = "wendal",
id = 123,
email = "abc@qq.com"
}
sys.waitUntil("pb_file_exists") -- 等待文件加载事件
local pbdata = protobuf.encode("Person", tb)
-- 使用 protobuf 编码
if pbdata then
log.info("protobuf", "encode", #pbdata, (pbdata:toHex())) -- 打印编码后的数据长度和十六进制表示
end
local jdata = json.encode(tb)
-- 使用 JSON 编码
if jdata then
log.info("json", #jdata, jdata) -- 打印 JSON 编码的数据长度
end
6.1.4 数据解码
解码 PROTOBUF 数据,将编码后的 pbdata
解码成 Lua 表 re
,并将其转换为 JSON 格式进行打印:
local re = protobuf.decode("Person", pbdata) -- 解码数据
if re then
log.info("protobuf", "decode", json.encode(re)) -- 打印解码后的数据
end
6.2 完整程序清单
注:完整复制后保存为 main.lua,可直接使用
-- main.lua文件
-- LuaTools需要PROJECT和VERSION这两个信息
PROJECT = "protobuf_demo"
VERSION = "1.0.0"
-- sys库是标配
sys = require("sys")
log.info("main", PROJECT, VERSION)
sys.taskInit(function()
-- 如果没有这个库, 就云编译一份吧: https://wiki.luatos.com/develop/compile/Cloud_compilation.html
if not protobuf then
log.info("protobuf", "this demo need protobuf lib")
return
end
-- 加载 pb 文件, 这个是从pbtxt 转换得到的
-- 下载资源到模块时不需要下载pbtxt,需要下载person.pb文件
-- 转换命令: protoc.exe -o person.pb person.pbtxt
-- protoc.exe 下载地址: https://github.com/protocolbuffers/protobuf/releases
local pb_file = "/luadb/person.pb"
if io.exists(pb_file) then
protobuf.load(io.readFile(pb_file))
--如果该文件存在,会发布一个事件 pb_file_exists
sys.publish("pb_file_exists")
else
log.info("protobuf","Failed to load file")
end
local tb = {
name = "wendal",
id = 123,
email = "abc@qq.com"
}
sys.waitUntil("pb_file_exists")
sys.wait(1000)
-- 用 protobuf 编码数据
local pbdata = protobuf.encode("Person", tb)
if pbdata then
-- 打印数据长度. 编码后的数据含不可见字符, toHex是方便显示
log.info("protobuf", "encode", #pbdata, (pbdata:toHex()))
end
-- 用 json 编码数据, 用于对比大小
local jdata = json.encode(tb)
if jdata then
log.info("json", #jdata, jdata)
end
-- 可见 protobuffs 比 json 节省很多空间
-- 后续是演示解码
local re = protobuf.decode("Person", pbdata)
if re then
-- 打印数据, 因为table不能直接显示, 这里转成json来显示
log.info("protobuf", "decode", json.encode(re))
end
end)
-- 用户代码已结束---------------------------------------------
-- 结尾总是这一句
sys.run()
-- sys.run()之后后面不要加任何语句!!!!!
七、功能验证
7.1 下载固件界面
7.2 找不到文件 person.pb 报错日志
7.3 编码为 PROTOBUF 数据并打印出来
7.4 使用 JSON 对数据进行编码并打印出来
7.5 解码 PROTOBUF 数据,并将其转换为 JSON 格式进行打印
总结
至此,我们已使用 Air8101 开发板完成了 如何使用 PROTOBUF 编解码数据。