2016-07-12 1 views
4

J'utilise SerializeToString sur mes objets Protobuf, puis stocke la chaîne dans un DB.Stockage d'un ensemble d'objets protobuf sérialisés

Cependant, parfois j'ai un tableau de tels objets. Je voudrais stocker tout le tableau sérialisé, et pour cela j'ai besoin d'une chaîne de séparateur entre les chaînes sérialisées.

Selon le documentation que j'ai vu, la chaîne est juste un tableau d'octets, et donc je n'ai rien promis au sujet de son contenu.

Quelle serait la meilleure approche ici? Je ne connais pas la longueur du tableau car des objets peuvent y être ajoutés au fur et à mesure, et je veux qu'il soit stocké dans la base de données tout au long du processus.

+1

Que diriez-vous de préfixer le flux de chaîne avec des informations de longueur? – Arunmu

+0

Je pourrais préfixer un sizeof (int) devant chaque chaîne. On dirait que ça devrait marcher. Je vais essayer de poster des résultats si cela va fonctionner – Mugen

Répondre

3

Supposons, votre protobuf message ressemble à ceci:

message Object 
{ 
    ... = 1; 
    ... = 2; 
    ... = 3; 
} 

Ensuite, dans le même fichier introduisons 1 plus message qui est une collection de ces Object s.

message Objects 
{ 
    repeated Object array = 1; 
} 

Par conséquent, lorsque vous avez beaucoup d'éléments, vous pouvez simplement utiliser le Objects et utiliser SerializeAsString() sur Objects lui-même. Cela permettra d'économiser vos efforts de série individuelle Object séparément et en mettant votre propre délimiteur à la main. Vous pouvez sérialiser tous les Object en utilisant une instance unique de Objects.
Avec cette approche, vous êtes déléguer tous les travaux de sérialisation & d'analyse également à la bibliothèque Protobuf. Je l'utilise dans mon projet et ça fonctionne comme un charme. En outre, l'utilisation judicieuse de Objects permettra également d'éviter de faire des copies supplémentaires de Object. Vous pouvez ajouter des éléments à cela et accéder à l'aide de l'indexation. Les champs repeated de protobufs sont conformes à C++ 11, vous pouvez donc l'utiliser avec des itérateurs ou une boucle for améliorée.


important de noter que, lorsque vous stockez la sortie du Objects::SerializeAsString() dans un fichier, vous devez d'abord saisir la longueur de cette string suivi de la chaîne sérialisée réelle. Pendant la lecture, vous pouvez lire la longueur en premier suivie par le nombre total d'octets. Pour la facilité d'utilisation, je l'ai étendu la std::fstream et surcharge les méthodes suivantes:

struct fstreamEncoded : std::fstream 
{ 
    // other methods 
    void // returns `void` to avoid multiple `<<` in a single line 
    operator<< (const string& content) 
    { // below casting would avoid recursive calling of this method 
     // adding `length() + 1` to include the protobuf's last character as well 
     static_cast<std::fstream&>(*this) << (content.length() + 1) << "\n" << content << std::endl; 
    } 

    string 
    getline() 
    { 
     char length_[20] = {}; 
     std::istream::getline(length_, sizeof(length_) - 1); 
     if(*length_ == 0) 
     return ""; 

     const size_t length = std::atol(length_); // length of encoded input 
     string content(length, 0); // resize the `string` 
     read(&content[0], length); // member of `class istream` 
     return content; 
    } 
} 

Au-dessus est juste une illustration. Vous pouvez suivre en fonction des besoins de votre projet.

+0

Bien que ce soit une belle solution, ce serait un gaspillage en termes d'ajout de données sérialisées les uns aux autres. Je devrais désérialiser, ajouter et re-sérialiser – Mugen

+0

@Mugen, il n'y a pas de gaspillage de ressources, sauf si vous décidez de garder 'Object's et' Objects' séparés.De plus, il n'y a pas de «données sérialisées annexes», mais simplement «données annexes». Ensuite, vous pouvez sérialiser uniquement lorsque vous stockez dans un fichier ou que vous passez à un autre domaine. De même désérialiser. Si vous trouvez un gaspillage de ressources, alors je suggère de mettre à jour ici dans le commentaire ou votre Q avec l'exemple pertinent, afin que je puisse effacer vos doutes. – iammilind

+2

@Mugen En fait, en raison des détails du format protobuf, si vous concaténez deux instances de 'Objects' (comme défini ci-dessus), cela équivaut exactement à concaténer le champ répété' array' en une seule instance et en sérialisant cela. Donc vous n'avez pas à désérialiser pour l'ajouter! –

1

Si vous ne pouvez pas garantir que votre séparateur serait unique au contenu des données sérialisées, alors j'ajouterais un élément de taille au début de chaque objet indiquant combien de temps la chaîne suivante est.