Yes, it is possible to serialize multiple protocol buffer messages
into a binary file and then load them from one by one.

Please see below my sample:

1. The file that describe the message I want to serialize:

message Person {
  required int32 id = 1;
  required string name = 2;
  optional string email = 3;
  required GendreType gendre = 4;

  enum GendreType {
    M = 1;
    F = 2;
  }
}

message Catalog {
  repeated Person persons = 1;
}

2. The code that load the messages one by one (please see the
functions saveMultipleMessages and loadMultipleMessages)  or at once:

#include <cassert>
#include <iostream>
#include <fstream>
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/io/zero_copy_stream.h>
#include <google/protobuf/io/zero_copy_stream_impl.h>
#include <google/protobuf/io/coded_stream.h>
#include "person.pb.h"

using namespace std;

static const char *gendres[] = {"M", "F"};

//
bool saveMultipleMessages(const char *fileName);
bool loadMultipleMessages(const char *fileName);
//

int main()
{
    GOOGLE_PROTOBUF_VERIFY_VERSION;

    fstream out("person.pb", ios::out | ios::binary | ios::trunc);

    // the container of person objects
    Catalog catalog;

    // add person #1
    Person *p = catalog.add_persons();

    p->set_id(23);
    p->set_name("Bob");
    p->set_email("b...@mail.com");
    p->set_gendre(Person::M);

    // add person #2
    p = catalog.add_persons();

    p->set_id(24);
    p->set_name("Foo");
    p->set_gendre(Person::F);

    // serialize the container of the person objects
    catalog.SerializeToOstream(&out);
    out.close();

    // deserialize the container of person objects
    Catalog cat1;

    fstream in("person.pb", ios::in | ios::binary);
    if (!cat1.ParseFromIstream(&in))
    {
        cerr << "Failed to parse person.pb" << endl;
        exit(1);
    }

    for (int i = 0; i < cat1.persons_size(); ++i)
    {
        Person p = cat1.persons(i);

        cout << "ID: " << p.id() << endl;
        cout << "name: " << p.name() << endl;
        cout << "gendre: " << gendres[p.gendre()-1] << endl;
        if (p.has_email())
        {
            cout << "e-mail: " << p.email() << endl;
        }

        cout << endl;
    }
    in.close();

    //
    if (saveMultipleMessages("person1.pb"))
    {
        loadMultipleMessages("person1.pb");
    }

    google::protobuf::ShutdownProtobufLibrary();

    return 0;
}

//
bool saveMultipleMessages(const char *fileName)
{
    fstream out(fileName, ios::out | ios::trunc | ios::binary);
    if (!out)
    {
        cerr << "failed to open " << fileName << endl;
        return false;
    }

    ::google::protobuf::io::ZeroCopyOutputStream *raw_out =
new ::google::protobuf::io::OstreamOutputStream(&out);
    ::google::protobuf::io::CodedOutputStream *coded_out =
new ::google::protobuf::io::CodedOutputStream(raw_out);

    // save the number of the messages to be serialized into the
output file
    coded_out->WriteVarint32(2);

    std::string s;

    // message #1
    Person p;
    p.set_id(1);
    p.set_name("Bob");
    p.set_gendre(Person::M);

    p.SerializeToString(&s);

    coded_out->WriteVarint32(s.size());
    coded_out->WriteRaw(s.data(), s.size()); // ->WriteString(s)
    //

    // message #2
    p.set_id(2);
    p.set_name("Jane");
    p.set_email("j...@kinky.com");
    p.set_gendre(Person::F);

    p.SerializeToString(&s);

    coded_out->WriteVarint32(s.size());
    coded_out->WriteString(s);
    //

    delete coded_out;
    delete raw_out;
    out.close();

    return true;
}

//
bool loadMultipleMessages(const char *fileName)
{
    fstream in(fileName, ios::in | ios::binary);
    if (!in)
    {
        cerr << "failed to open " << fileName << endl;
        return false;
    }

    ::google::protobuf::io::ZeroCopyInputStream *raw_in =
new ::google::protobuf::io::IstreamInputStream(&in);
    ::google::protobuf::io::CodedInputStream *coded_in =
new ::google::protobuf::io::CodedInputStream(raw_in);

    uint32_t n;
    coded_in->ReadVarint32(&n);
    cout << "#" << n << endl;

    //
    std::string s;

    for (uint32_t i = 0; i < n; ++i)
    {
        uint32_t msgSize;
        coded_in->ReadVarint32(&msgSize);

        if ((msgSize > 0) &&
            (coded_in->ReadString(&s, msgSize)))
        {
            //
            Person p;
            p.ParseFromString(s);
            //

            cout << "ID: " << p.id() << endl;
            cout << "name: " << p.name() << endl;
            cout << "gendre: " << gendres[p.gendre()-1] << endl;
            if (p.has_email())
            {
                cout << "e-mail: " << p.email() << endl;
            }

            cout << endl;
        }
    }

    delete coded_in;
    delete raw_in;
    in.close();

    return true;
}

3. I hope this is the aspect you asked for.

Florin

On Jan 15, 6:05 am, samarules <akm...@gmail.com> wrote:
> Hi All,
>
> I have what I believe is a simple task: write multiple protocol buffer
> messages into a single binary file and then read them back
> sequentially. When reading, I should not have to load the entire file
> in memory but read  each protobuf object one at a time (with some
> buffering). An example application would to be store a large number of
> documents in a file, where each document is a single protobuf message.
>
> Is this functionality available in C++?
>
> Zia
-- 
You received this message because you are subscribed to the Google Groups 
"Protocol Buffers" group.
To post to this group, send email to proto...@googlegroups.com.
To unsubscribe from this group, send email to 
protobuf+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/protobuf?hl=en.


Reply via email to