【问题标题】:Problems with repeated field in Protobuf. What is a better way to use the repeated field for serialization/deserialization?Protobuf 中重复字段的问题。使用重复字段进行序列化/反序列化的更好方法是什么?
【发布时间】:2020-04-26 03:48:56
【问题描述】:

考虑以下 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;
}

现在我想将一些随机数据序列化到一个文件中。例如,我将拥有一个带有多个传感器的设备,因此 proto 中的重复文件。我使用以下代码。

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();
}

【问题讨论】:

  • add_sensors() 添加一个传感器。因此,您每次通话都会得到一个,而 12 是正确的
  • @foreknownas_463035818 我注意到了。除了使用 device.add_sensors()->set_* 之外,我没有看到任何其他方法来设置传感器的值。否则将如何完成?

标签: c++ protocol-buffers protobuf-c proto3


【解决方案1】:

代替

    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 个传感器,我想这是您的意图,并且所有传感器都将拥有每个数据成员集。

【讨论】:

  • 出于某种特殊原因,我忽略了这一点! :s
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-06-29
  • 1970-01-01
  • 2012-02-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多