Reputation: 165
Consider the following sensor.proto file that makes use of the repeated field to initialize multiple messages.
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;
}
Now I want to serialize some random data to a file. As an example, I will have one device with multiple sensors, hence the repeated file in the proto. I use the following code.
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();
}
To parse the data and print out the result I use the following:
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();
}
A main file to reproduce the results:
#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;
}
It doesn't seem intuitive to iterate through the total sensor size and getting the correct index to display the appropriate field. Even by checking
std::cout << device.sensors_size() << std::endl;
will output size 12 which it does not feel correct, or
std::cout << decice.sensors(2).name() << std::endl;
will not output anything since it is in the incorrect index. What is a better way to use the libprotobuf to define a repeated field for serializing/deserializing better.
EDIT: As the answer suggests, serializing to the file should be as
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();
}
Upvotes: 0
Views: 2698
Reputation: 701
Instead of
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);
you should write
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);
This way you will have 3 sensors, which is your intent I suppose, and all of them will have every data member set.
Upvotes: 3