2

I got a source code of Protobuf-net that serializes an object to a file.

var person = new Person {
        Id = 12345, Name = "Fred",
        Address = new Address {
            Line1 = "Flat 1",
            Line2 = "The Meadows"
        }
    };
    using (var file = File.Create("person.bin")) {
        ProtoBuf.Serializer.Serialize(file, person);
    }

But suppose i have two instance of Person that i want to serialize into a single file. how can i do that?

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
Rezoan
  • 1,745
  • 22
  • 51
  • I got the solution in http://stackoverflow.com/questions/817641/i-have-a-single-file-and-need-to-serialize-multiple-objects-randomly-how-can-i thanks Agin to Marc Gravell – Rezoan Mar 07 '13 at 08:11

1 Answers1

7

protobuf, in the pure sense, does not have any "terminator" except the end of a file (this is so that objects can be merged/combined simply by concatenating the blobs).

However, we can inject our own markers, for example by prefixing every object with the length of the data that follows.

protobuf-net wraps this up by exposing a SerializeWithLengthPrefix method. There are various methods to deserialize from this, but the simplest is DeserializeItems, which gives you a streaming sequence of objects in turn (lazily spooling from the stream in the iterator - so it is perfectly suitable for very large sequences).

For info, so you can see how this is implemented: if you use PrefixStyle.Base128 and a positive fieldNumber, then on the wire this looks the same as if you had a wrapper object like:

[ProtoContract]
public class DoesNotExist {
    [ProtoMember({fieldNumber})]
    public List<Person> People {get;set;}
}

the key differences being that no actual DoesNotExist type/instance exists, and no List<T> is created - you just get the Person instances.

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • Marc could you please answer what is the effect of field number(Last argument) (value=0) in Serializer.SerializeWithLengthPrefix(s, command1, PrefixStyle.Base128, 0); – Rezoan Mar 07 '13 at 08:15
  • @Rezoan this mainly applies when using a `Base128` prefix; if a positive number is supplied, then the prefix is written in a way that makes the entire composite stream *itself* a valid protobuf stream, as per the `DoesNotExist` example. One interesting use of this is that it allows you to write heterogeneous objects to the same stream and take them off in sequence - i.e. you could write a `Person`, an `Order`, a `Person`, a `Person` and then an `Address`. You would need to use the non-generic API and a type-resolver to take these back off the stream, but it is really handy for ... – Marc Gravell Mar 07 '13 at 08:17
  • @Rezoan ...things like message-based sockets or RPC; each operation can have a different field-number, which you process separately. I personally always like to include a field number *just because I like having the entire stream be valid protobuf* – Marc Gravell Mar 07 '13 at 08:19
  • thanks. i will back to you very soon with another problem. =D – Rezoan Mar 07 '13 at 08:22
  • Just to be clear i'm asking a question @Marc. if i serialize this person object using c# protbuf-net to a file. does it easily can be deserializable using c++ Google's protocol buffer? – Rezoan Mar 07 '13 at 08:29
  • @Rezoan k; that is a more interesting question :) The answer is ultimately "yes", but: you might have to handle reading the length prefixes manually. Alternatively, if you tell c++ about the `DoesNotExist`, you can **write** (in C#) via `SerializeWithLengthPrefix`, but deserialize in c++ by asking it to deserialize a `DoesNotExist` - does that make sense? – Marc Gravell Mar 07 '13 at 08:33
  • yes i have to handle length prefix manually. i have got a task that need to serialize multiple struct into a single file using google protobuffer and again this file need to be deserialized. serialization part shuld be written in c# and deserialization part shuld be in c++. thats why im asking this question to you. – Rezoan Mar 07 '13 at 08:48