Protobuf 动态加载 .pb 文件并操作 Message

Protobuf 动态加载 .pb 文件并操作 Message

之前写了《Protobuf 动态加载 .proto 文件并操作 Message》。除了直接读取 .proto 文件之外,还有一种类似的方法。先把 .proto 文件编译成 .pb 文件,再读取 .pb 文件。这种方法虽然比直接读取 .proto 多了一步,但是在运行期加载更快。
仍然使用之前的的 .proto 文件作为示例。使用 protoc.proto 文件编译为 .pb 文件。

./3rdparty/bin/protoc -I./proto -oaddressbook.pb --include_imports ./proto/addressbook.proto

注意,这里有两个 .proto 文件,应该选择没有被依赖的 .proto 文件作为参数,并且添加 --include_imports 选项。这样,所有 .proto 文件及其依赖的 .proto 文件都被编进同一个 .pb 文件。

#include <iostream>
#include <fstream>
#include <google/protobuf/dynamic_message.h>
#include <google/protobuf/util/json_util.h>
#include <google/protobuf/descriptor.pb.h>

using namespace google::protobuf;

int main()
{
    std::ifstream pb_file("./addressbook.pb", std::ios::binary);
    if (!pb_file.is_open())
    {
        return -1;
    }

    FileDescriptorSet file_descriptor_set;
    if (!file_descriptor_set.ParseFromIstream(&pb_file)) {
        return -1;
    }

    DescriptorPool pool;
    for (int i = 0; i < file_descriptor_set.file_size(); ++i) {
        pool.BuildFile(file_descriptor_set.file(i));
    }

    const Descriptor* person_descriptor = pool.FindMessageTypeByName("tutorial.Person");
    
    DynamicMessageFactory message_factory;
    const Message* default_person = message_factory.GetPrototype(person_descriptor);
    Message* person = default_person->New();

    const Reflection* reflection = person->GetReflection();
    reflection->SetString(person, person_descriptor->FindFieldByName("name"), "abc");
    reflection->SetInt32(person, person_descriptor->FindFieldByName("id"), 123456);
    reflection->SetString(person, person_descriptor->FindFieldByName("email"), "abc@163.com");

    util::JsonPrintOptions json_options;
    json_options.add_whitespace = true;
    json_options.always_print_primitive_fields = true;
    json_options.preserve_proto_field_names = true;
    std::string output;
    util::MessageToJsonString(*person, &output, json_options);
    std::cout << "====== Person data ======" << std::endl;
    std::cout << output;

    delete person;
}

输出

====== Person data ======
{
 "name": "abc",
 "id": 123456,
 "email": "abc@163.com",
 "phones": []
}
hmoban主题是根据ripro二开的主题,极致后台体验,无插件,集成会员系统
自学咖网 » Protobuf 动态加载 .pb 文件并操作 Message