First, there's a list of PB key features that I find crucial:
- Data structures are described using a very simple .proto files (what a relief considering the verbosity of DTD/XSDs).
- .proto files are then used to generate data access classes (no need for hand-written loaders/savers any more).
- The produced binary stream is very compact and efficient, and can be easily translated back and forth to a human readable JSON-like textual form, using an offline compiler (this is a killer feature that allows one to edit/hack the binary files in a regular text editor or more importantly use a scripting language to make various data transformations if necessary = BIG WIN!).
- The data access classes can be generated for both of my favourite languages: C++ (run-time) and Python (tools).
- PB sources can be directly dropped into and existing project (no need to maintain the countless number of lib variants on all the platforms, I find this very convenient in general as it dramatically reduces the maintenance cost, I'm a big fan of single-source-file amalgamated libs, but that's a completely different story...).
- Create an empty console project.
- Add '.' to the include directories.
- From 'protobuf-2.4.1.zip/vsprojects' copy './config.h'.
- From 'protobuf-2.4.1.zip/src/' copy:
- './google/protobuf/*.*'
- './google/protobuf/io/*.*'
- './google/protobuf/stubs/*.*'
- Delete:
- './google/protobuf/test_util.h&cc'
- './google/protobuf/test_util_lite.h&cc'
- Delete the unit-test related stuff, everything matching: '*_unittest.*', '*.proto'.
- Add all the '*.h' and '*.cc' to the project, preserving the directory structure.
- From 'protoc-2.4.1-win32.zip' also copy './protoc.exe'.
Code: Select all
package business;
message Employee
{
required string first_name = 1;
required string last_name = 2;
required string email = 3;
}
message Company
{
required string name = 1;
optional string url = 2;
repeated Employee employee = 3;
}
Code: Select all
protoc.exe -I=. --cpp_out=. business.proto
Code: Select all
business.pb.h
business.pb.cc
Now, it's time to test our effort. There's nothing easier than filling in a demo company object, saving it to 'company.bin' and loading it back from the binary file, as shows the example below: VIEW THE CODE BELOW IN FULL-SCREEN (protobuf_sample.cpp)
Code: Select all
/*
(c) 2012 +++ Filip Stoklas, aka FipS, http://www.4FipS.com +++
THIS CODE IS FREE - LICENSED UNDER THE MIT LICENSE
ARTICLE URL: http://forums.4fips.com/viewtopic.php?f=3&t=807
*/
#include <iostream>
#include <fstream>
#include "business.pb.h"
using namespace std;
/// Saves a demo company object to 'company.bin'.
void save()
{
business::Company company;
company.set_name("Example Ltd.");
company.set_url("http://www.example.com");
// 1st employee
{
business::Employee *employee = company.add_employee();
employee->set_first_name("John");
employee->set_last_name("Doe");
employee->set_email("john.doe@example.com");
}
// 2nd employee
{
business::Employee *employee = company.add_employee();
employee->set_first_name("Jane");
employee->set_last_name("Roe");
employee->set_email("jane.roe@example.com");
}
fstream output("company.bin", ios::out | ios::trunc | ios::binary);
company.SerializeToOstream(&output);
}
/// Loads a demo company object from 'company.bin' and dumps its data.
void load()
{
business::Company company;
fstream input("company.bin", ios::in | ios::binary);
company.ParseFromIstream(&input);
cout << "Company: " << company.name() << "\n";
cout << "URL: " << (company.has_url() ? company.url() : "N/A") << "\n";
cout << "\nEmployees: \n\n";
for(int i = 0, n = company.employee_size(); i < n; ++i)
{
const business::Employee &employee = company.employee(i);
cout << "First name: " << employee.first_name() << "\n";
cout << "Last name: " << employee.last_name() << "\n";
cout << "Email: " << employee.email() << "\n";
cout << "\n";
}
}
int main()
{
save();
load();
return 0;
}
// output:
// Company: Example Ltd.
// URL: http://www.example.com
//
// Employees:
//
// First name: John
// Last name: Doe
// Email: john.doe@example.com
// First name: Jane
// Last name: Roe
// Email: jane.roe@example.com
Code: Select all
protoc.exe business.proto --decode=business.Company < company.bin > company.txt
Code: Select all
name: "Example Ltd."
url: "http://www.example.com"
employee {
first_name: "John"
last_name: "Doe"
email: "john.doe@example.com"
}
employee {
first_name: "Jane"
last_name: "Roe"
email: "jane.roe@example.com"
}
Code: Select all
protoc.exe business.proto --encode=business.Company < company.txt > company.bin