我想使用protobuf并以文本格式创建序列化输出文件以进行测试和替换json。我无法弄清楚如何自己编写它并寻找示例。 这是二进制输出的一个:
#include <iostream>
#include <fstream>
#include <string>
#include "addressbook.pb.h"
using namespace std;
// This function fills in a Person message based on user input.
void PromptForAddress(tutorial::Person* person) {
cout << "Enter person ID number: ";
int id;
cin >> id;
person->set_id(id);
cin.ignore(256, '\n');
cout << "Enter name: ";
getline(cin, *person->mutable_name());
cout << "Enter email address (blank for none): ";
string email;
getline(cin, email);
if (!email.empty()) {
person->set_email(email);
}
while (true) {
cout << "Enter a phone number (or leave blank to finish): ";
string number;
getline(cin, number);
if (number.empty()) {
break;
}
tutorial::Person::PhoneNumber* phone_number = person->add_phones();
phone_number->set_number(number);
cout << "Is this a mobile, home, or work phone? ";
string type;
getline(cin, type);
if (type == "mobile") {
phone_number->set_type(tutorial::Person::MOBILE);
} else if (type == "home") {
phone_number->set_type(tutorial::Person::HOME);
} else if (type == "work") {
phone_number->set_type(tutorial::Person::WORK);
} else {
cout << "Unknown phone type. Using default." << endl;
}
}
}
// Main function: Reads the entire address book from a file,
// adds one person based on user input, then writes it back out to the same
// file.
int main(int argc, char* argv[]) {
// Verify that the version of the library that we linked against is
// compatible with the version of the headers we compiled against.
GOOGLE_PROTOBUF_VERIFY_VERSION;
if (argc != 2) {
cerr << "Usage: " << argv[0] << " ADDRESS_BOOK_FILE" << endl;
return -1;
}
tutorial::AddressBook address_book;
{
// Read the existing address book.
fstream input(argv[1], ios::in | ios::binary);
if (!input) {
cout << argv[1] << ": File not found. Creating a new file." << endl;
} else if (!address_book.ParseFromIstream(&input)) {
cerr << "Failed to parse address book." << endl;
return -1;
}
}
// Add an address.
PromptForAddress(address_book.add_people());
{
// Write the new address book back to disk.
fstream output(argv[1], ios::out | ios::trunc | ios::binary);
if (!address_book.SerializeToOstream(&output)) {
cerr << "Failed to write address book." << endl;
return -1;
}
}
// Optional: Delete all global objects allocated by libprotobuf.
google::protobuf::ShutdownProtobufLibrary();
return 0;
}
我可以在这一个中做一些小的改动,以文本格式输出或者需要做些什么吗?请建议所需的更改或代码存在的任何链接(使用任何语言)。
答案 0 :(得分:6)
保证调试字符串输出是有效的文本序列化格式,但不关心协议消息是否实际有效:
std::string s = msg.DebugString(); // or ShortDebugString
如果您想验证,请使用TextFormat::PrintToString
:
#include <google/protobuf/text_format.h>
if (std::string s; google::protobuf::TextFormat::PrintToString(msg, &s)) {
std::cout << "Your message: " << s;
} else {
std::cerr << "Message not valid (partial content: "
<< msg.ShortDebugString() << ")\n";
}
json_util.h中提供了JSON互操作工具。
答案 1 :(得分:2)
此代码将protobuf消息序列化为JSON并将JSON反序列化为protobuf消息。
这是直接从生产代码中提取的(我拥有并在此授予您使用许可,但请相信我)。
这与protobuf 3有关。
struct pretty_json_type {
void operator()(google::protobuf::util::JsonOptions& opts) const {
opts.add_whitespace = true;
}
};
static constexpr pretty_json_type pretty_json{};
struct compact_json_type {
void operator()(google::protobuf::util::JsonOptions& opts) const {
opts.add_whitespace = false;
}
};
static constexpr compact_json_type compact_json{};
struct include_defaults_type {
void operator()(google::protobuf::util::JsonOptions& opts) const {
opts.always_print_primitive_fields = true;
}
};
static constexpr include_defaults_type include_defaults{};
template<class...Options>
auto json_options(Options&&...options)
{
google::protobuf::util::JsonOptions opts;
using expand = int [];
void(expand{
0,
((options(opts)),0)...
});
return opts;
}
std::string as_json(const google::protobuf::Message& msg,
google::protobuf::util::JsonOptions opts = json_options(pretty_json,
include_defaults));
std::string as_json(const google::protobuf::Message* msg,
google::protobuf::util::JsonOptions opts = json_options(pretty_json,
include_defaults));
google::protobuf::Message& from_json(google::protobuf::Message& msg,
const char* first,
std::size_t size);
inline
decltype(auto) from_json(google::protobuf::Message& msg,
const std::string& json)
{
return from_json(msg, json.data(), json.length());
}
std::string as_json(const google::protobuf::Message& msg,
google::protobuf::util::JsonOptions opts)
{
namespace pb = google::protobuf;
namespace pbu = google::protobuf::util;
auto buffer = msg.SerializeAsString();
std::string result;
pb::io::ArrayInputStream zistream(buffer.data(), buffer.size());
auto resolver = std::unique_ptr<pbu::TypeResolver> {
pbu::NewTypeResolverForDescriptorPool("",
pb::DescriptorPool::generated_pool())
};
auto status = google::protobuf::util::BinaryToJsonString(resolver.get(),
"/" + msg.GetDescriptor()->full_name(),
buffer,
std::addressof(result),
opts);
if (!status.ok())
{
std::ostringstream ss;
ss << status;
throw std::runtime_error(ss.str());
}
return result;
}
std::string as_json(const google::protobuf::Message* msg,
google::protobuf::util::JsonOptions opts)
{
return as_json(*msg, opts);
}
google::protobuf::Message& from_json(google::protobuf::Message& msg,
const char* first,
std::size_t size)
{
namespace pb = google::protobuf;
namespace pbu = google::protobuf::util;
auto resolver = std::unique_ptr<pbu::TypeResolver> {
pbu::NewTypeResolverForDescriptorPool("", pb::DescriptorPool::generated_pool())
};
auto zistream = std::make_unique<pb::io::ArrayInputStream>(first,
size);
auto binary_buffer = std::string {};
binary_buffer.reserve(size);
auto zostream = std::make_unique<pb::io::StringOutputStream>(std::addressof(binary_buffer));
auto status = pbu::JsonToBinaryStream(resolver.get(),
"/" + msg.GetDescriptor()->full_name(),
zistream.get(), zostream.get());
zistream.reset();
zostream.reset();
if (msg.ParseFromString(binary_buffer))
{
return msg;
}
throw std::runtime_error("invalid message");
}
答案 2 :(得分:1)
要将消息通过三行代码转换为JSON,请执行以下操作-
#include <google/protobuf/util/json_util.h>
static std::string ProtoToJson(const google::protobuf::Message& proto)
{
std::string json;
google::protobuf::util::MessageToJsonString(proto, &json);
return json;
}