Protobuf 中重复字段的问题。将重复字段用于 serialization/deserialization 的更好方法是什么?

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

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

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 为 serializing/deserializing 定义重复字段的更好方法是什么?


编辑:正如答案所暗示的,序列化到文件应该是


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