web-dev-qa-db-fra.com

Tampons de protocole Google - Stockage des messages dans un fichier

J'utilise le tampon de protocole Google pour sérialiser les données du marché boursier (c.-à-d. Horodatage, offres, champs de demande). Je peux stocker un message dans un fichier et le désérialiser sans problème.

Comment puis-je stocker plusieurs messages dans un seul fichier? Je ne sais pas comment je peux séparer les messages. Je dois pouvoir ajouter de nouveaux messages au fichier à la volée.

36
DD.

Je recommanderais d'utiliser les méthodes writeDelimitedTo(OutputStream) et parseDelimitedFrom(InputStream) sur les objets Message. writeDelimitedTo écrit la longueur du message avant le message lui-même; parseDelimitedFrom utilise alors cette longueur pour lire un seul message et pas plus loin. Cela permet à plusieurs messages d'être écrits dans un seul OutputStream pour ensuite être analysés séparément. Pour plus d'informations, voir https://developers.google.com/protocol-buffers/docs/reference/Java/com/google/protobuf/MessageLite#writeDelimitedTo (Java.io.OutputStream)

30
Josh Hansen

De la documentation:

http://code.google.com/apis/protocolbuffers/docs/techniques.html#streaming

Streaming de plusieurs messages

Si vous souhaitez écrire plusieurs messages dans un seul fichier ou flux, c'est à vous de savoir où se termine un message et où commence le suivant. Le format de fil du tampon de protocole ne se délimite pas automatiquement, les analyseurs de tampon de protocole ne peuvent donc pas déterminer par eux-mêmes où se termine un message. La façon la plus simple de résoudre ce problème consiste à écrire la taille de chaque message avant d'écrire le message lui-même. Lorsque vous lisez les messages, vous lisez la taille, puis lisez les octets dans un tampon séparé, puis analysez à partir de ce tampon. (Si vous voulez éviter de copier des octets dans un tampon séparé, consultez la classe CodedInputStream (en C++ et Java) qui peut être invitée à limiter les lectures à un certain nombre d'octets.)

13
DD.

Protobuf n'inclut pas de terminateur par enregistrement le plus externe, vous devez donc le faire vous-même. L'approche la plus simple consiste à préfixer les données avec la longueur de l'enregistrement qui suit. Personnellement, j'ai tendance à utiliser l'approche d'écriture d'un en-tête de chaîne (pour un numéro de champ arbitraire), puis la longueur comme un "varint" - cela signifie que le document entier est alors lui-même un protobuf valide, et pourrait être consommé comme un objet avec un élément "répété", cependant, juste un marqueur de longueur fixe (typiquement petit-boutien 32 bits) ferait aussi bien. Avec un tel stockage, il peut être ajouté selon vos besoins.

6
Marc Gravell

Si vous recherchez une solution C++, Kenton Varda a soumis un patch à protobuf vers août 2015 qui ajoute la prise en charge des appels writeDelimitedTo () et readDelimitedFrom () qui sérialiseront/désérialiseront une séquence de messages proto à/à partir d'un fichier d'une manière compatible avec la version Java de ces appels. Malheureusement, ce correctif n'a pas encore été approuvé, donc si vous voulez la fonctionnalité, vous devrez le fusionner vous-même .

Une autre option est que Google a ouvert le code de lecture/écriture de fichiers protobuf à travers d'autres projets. La bibliothèque or-tools , par exemple, contient les classes RecordReader et RecordWriter qui sérialisent/désérialisent un flux de proto dans un fichier.

Si vous souhaitez des versions autonomes de ces classes qui n'ont presque pas de dépendances externes, j'ai une fourchette de ou-tools qui ne contient que ces classes. Voir: https://github.com/moof2k/recordio

La lecture et l'écriture avec ces cours sont simples:

File* file = File::Open("proto.log", "w");
RecordWriter writer(file);
writer.WriteProtocolMessage(msg1);
writer.WriteProtocolMessage(msg2);
...
writer.Close();
5
moof2k