poniedziałek, 6 marca 2023

Serializacja Protobol Buffers (protobuf) danych przy pomocy biblioteki protobuf-net

 Protocol Buffers jest mechanizmem serializacji stworzonym przez Google. Założenie projektu opierało się na tym aby ilość danych wygenerowanych była jak najmniejsza, szybkość działania jak największa oraz nie były uzależnione od języka programowania czy użytej platformy. 

Można by powiedzieć, że jest to XML/JSON tylko w dużo lepszym wydaniu. Platforma .NET oferuje wiele narzędzi, które pozwalają tworzyć klasy na podstawie plików .proto. Na rynku istnieje także ciekawa biblioteka protobuf-net, która pozwala stworzyć kontrakt serializowanej klasy podobnie jak to ma się np. w przypadku XmlSerializera (za pomocą atrybutów).

Najłatwiej pokazać zasadę działania biblioteki na przykładzie. 

Na początek instalujemy protobuf-net:


Następnie definiujemy klasę którą chcemy zserializować: 

 [ProtoContract]  
 public class Person  
 {  
   [ProtoMember(1)]  
   public int Id { get; set; }  
   [ProtoMember(2)]  
   public string FirstName { get; set; }  
   [ProtoMember(3)]  
   public string LastName { get; set; }  
   [ProtoMember(4)]  
   public string Address { get; set; }  
   public override string ToString()  
   {  
     return $"{nameof(Id)}: {Id}, {nameof(FirstName)}: {FirstName}, {nameof(LastName)}: {LastName}, {nameof(Address)}: {Address}";  
   }  
 }  

Warto w tym miejscu wspomnieć o kilku aspektach:

  • ProtoContract - atrybut serializowanej klasy
  • ProtoMember(int i) - atrybut który przypisujemy poszczególnym właściwością klasy. Ważne aby numery nie powtarzały się dla tego samego typu (nawet w przypadku gdy dziedziczymy po tej klasie musimy pamiętać aby numery były unikalne). Unikalność jest na poziomie typu. Oznacza to, że dla kolejnego typu możemy rozpocząć znowu od 1. Nie warto używać dużych numerów początkowych. Im wyższy numer tym więcej danych do zapisu. 
Identyfikator (numer przypisany w atrybucie ProtoMember) jest jednym z najważniejszych elementów. Możemy zmienić nazwę pola, jednak dopóki jego numer pozostaje taki sam nie będzie problem z deserializacją danych. 

Teraz kawałek kodu który odpowiada za serializację / deserializację struktury danych. Dla przykładu dane zostaną zapisane do pliku:


 Person person = new()  
 {  
   Id = 1,  
   FirstName = "Mariusz",  
   LastName = "Kowalski",  
   Address = "Kraków, Malborska 10"  
 };  
 //1. Serializing data  
 var fileName = "person.bin";  
 using (var file = File.Create(fileName))  
 {  
   Serializer.Serialize(file, person);  
 }  
 //2. Deserializing data  
 using (var fileStream = File.OpenRead(fileName))  
 {  
   var deserializedPerson = Serializer.Deserialize<Person>(fileStream);  
   Console.WriteLine(deserializedPerson);  
 }  
 Console.ReadKey();  

Zarówno serializacja jak i deserializacja używa w tym przypadku klasy Serializer z biblioteki protobuf-net. Pracujemy na standardowych strumieniach danych - możemy je przekierować do pliku, przechować w pamięci czy też skonwertować do tablicy bajtów i przesłać np. do Pub/Suba.

Brak komentarzy:

Prześlij komentarz