Protobuf中重复字段的问题.使用重复字段进行序列化/反序列化的更好方法是什么?
Problems with repeated field in Protobuf. What is a better way to use the repeated field for serialization/deserialization?
请考虑以下 sensor.proto 文件,该文件使用重复字段来初始化多条消息。
syntax = "proto3";
package HUBSensors;
message Device {
string name = 1;
int32 id = 2;
message Sensor {
string name = 1;
double temperature = 2;
int32 humidity = 3;
enum SwitchLevel {
CLOSED = 0;
OPEN = 1;
}
SwitchLevel door = 4;
}
repeated Sensor sensors = 3;
}
现在我想将一些随机数据序列化到一个文件中。例如,我将有一个带有多个传感器的设备,因此原型中存在重复文件。我使用以下代码。
inline void serialize_to_file( const std::string &fileName )
{
HUBSensors::Device device;
device.set_name("HUB");
device.set_id(1234);
device.add_sensors()->set_name("Laboratory");
device.add_sensors()->set_temperature(23.3);
device.add_sensors()->set_humidity(2);
device.add_sensors()->set_door(HUBSensors::Device_Sensor_SwitchLevel_OPEN);
device.add_sensors()->set_name("Chml Laboratory");
device.add_sensors()->set_temperature(2.3);
device.add_sensors()->set_humidity(5);
device.add_sensors()->set_door(HUBSensors::Device_Sensor_SwitchLevel_CLOSED);
device.add_sensors()->set_name("GU Laboratory");
device.add_sensors()->set_temperature(8.3);
device.add_sensors()->set_humidity(2);
device.add_sensors()->set_door(HUBSensors::Device_Sensor_SwitchLevel_CLOSED);
std::ofstream ofs(fileName, std::ios_base::out | std::ios_base::binary );
device.SerializeToOstream( &ofs );
google::protobuf::ShutdownProtobufLibrary();
}
为了解析数据并打印出结果,我使用以下方法:
inline void parse_from_file( const std::string &fileName )
{
HUBSensors::Device device;
std::ifstream myFile;
myFile.exceptions( std::ifstream::badbit );
try {
myFile.open(fileName);
while ( myFile.good() )
{
device.ParseFromIstream( &myFile );
//std::cout << device.sensors_size() << std::endl;
std::cout << "Device Name : " << device.name() << std::endl;
std::cout << "^^^^^^" << std::endl;
for ( size_t i = 0; i < device.sensors_size(); i+=4)
{
std::cout << "Sensors Name : " << device.sensors(i).name() << std::endl;
std::cout << "Temperature : " << device.sensors(i+1).temperature() << std::endl;
std::cout << "Humidity : " << device.sensors(i+2).humidity() << std::endl;
std::cout << " Door Status : " << device.sensors(i+3).door() << std::endl;
std::cout << "^^^^^^" << std::endl;
}
}
}
catch ( const std::ifstream::failure &e )
{
std::cerr << "Error Occurred when accessing the file" << std::endl;
std::cout << e.what() << std::endl;
}
myFile.close();
google::protobuf::ShutdownProtobufLibrary();
}
用于重现结果的主文件:
#include <iostream>
#include <fstream>
#include <stdexcept>
#include "sensor.pb.h"
int main() {
GOOGLE_PROTOBUF_VERIFY_VERSION;
const std::string fileName = "./device.data";
serialize_to_file( fileName );
parse_from_file( fileName );
return 0;
}
遍历传感器总大小并获取正确的索引以显示适当的字段似乎并不直观。 即使通过检查
std::cout << device.sensors_size() << std::endl;
将输出感觉不正确的大小 12,或
std::cout << decice.sensors(2).name() << std::endl;
不会输出任何内容,因为它位于不正确的索引中。 使用libprotobuf定义重复字段以更好地序列化/反序列化的更好方法是什么。
编辑:正如答案所建议的那样,序列化到文件应该是
inline void serialize_to_file( const std::string &fileName )
{
HUBSensors::Device device;
device.set_name("HUB");
device.set_id(1234);
auto sensor1 = device.add_sensors();
auto sensor2 = device.add_sensors();
auto sensor3 = device.add_sensors();
sensor1->set_name("Laboratory");
sensor1->set_temperature(23.3);
sensor1->set_humidity(2);
sensor1->set_door(HUBSensors::Device_Sensor_SwitchLevel_CLOSED);
sensor2->set_name("GU Laboratory");
sensor2->set_temperature(44.3);
sensor2->set_humidity(4);
sensor2->set_door(HUBSensors::Device_Sensor_SwitchLevel_OPEN);
sensor3->set_name("Chml Laboratory");
sensor3->set_temperature(13.345);
sensor3->set_humidity(6);
sensor3->set_door(HUBSensors::Device_Sensor_SwitchLevel_CLOSED);
std::ofstream ofs(fileName, std::ios_base::out | std::ios_base::binary );
device.SerializeToOstream( &ofs );
google::protobuf::ShutdownProtobufLibrary();
}
而不是
device.add_sensors()->set_name("Laboratory");
device.add_sensors()->set_temperature(23.3);
device.add_sensors()->set_humidity(2);
device.add_sensors()->set_door(HUBSensors::Device_Sensor_SwitchLevel_OPEN);
你应该写
auto sensor = device.add_sensors();
sensor->set_name("Laboratory");
sensor->set_temperature(23.3);
sensor->set_humidity(2);
sensor->set_door(HUBSensors::Device_Sensor_SwitchLevel_OPEN);
这样,您将拥有 3 个传感器,我想这就是您的意图,并且所有传感器都将设置每个数据成员。
相关文章:
- 如何知道QDataStream不能反序列化某些内容
- 增强基于 XML class_id的反序列化
- 提升反序列化对象具有 nan 或 -nan 值
- 如何在 c++ 非托管代码中反序列化 byte[] 的 json 字符串?
- 如何反序列化数组?
- Protobuf中重复字段的问题.使用重复字段进行序列化/反序列化的更好方法是什么?
- 通过 tcp 发送 C# 类并在 C++ 上反序列化
- 预 C++20 位字段零初始化
- 序列化和反序列化boost共享指针
- 在C++中使用POCO和grain对多个对象进行反序列化
- C++中整数向量的序列化/反序列化
- 列出常量和数组结构字段的初始化
- 使用 Json 转换器反序列化 WCF 服务中的C++字符串
- 使用 QDataStream 对原始数据进行反序列化
- 使用协议缓冲区创建通用反序列化程序
- 如何在C++中从头开始反序列化文件(没有库)
- 在协议缓冲区 c++ 中反序列化字符串数组
- 序列化和反序列化位字段
- protobuf:对套接字进行连续序列化和反序列化
- 序列化和反序列化套接字中的结构