Протоколы Google Buffers - Хранение сообщений в файл - PullRequest
35 голосов
/ 05 февраля 2012

Я использую буфер протокола Google для сериализации данных фондового рынка (т. Е. Отметки времени, ставки, поля спроса).Я могу сохранить одно сообщение в файле и десериализовать его без проблем.

Как мне сохранить несколько сообщений в одном файле?Не уверен, как я могу отделить сообщения.Мне нужно иметь возможность добавлять новые сообщения в файл на лету.

Ответы [ 5 ]

29 голосов
/ 21 февраля 2013

Я бы рекомендовал использовать writeDelimitedTo(OutputStream) и parseDelimitedFrom(InputStream) методы для Message объектов. writeDelimitedTo записывает длину сообщения перед самим сообщением; parseDelimitedFrom затем использует эту длину для чтения только одного сообщения, а не дальше. Это позволяет записывать несколько сообщений в один OutputStream, а затем анализировать отдельно. Для получения дополнительной информации см. https://developers.google.com/protocol-buffers/docs/reference/java/com/google/protobuf/MessageLite#writeDelimitedTo(java.io.OutputStream)

12 голосов
/ 05 февраля 2012

Из документов:

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

Потоковая передача нескольких сообщений

Если вы хотите записать несколько сообщений в один файл или поток, этодо вас, чтобы отслеживать, где заканчивается одно сообщение и начинается следующее.Формат протокола Protocol Buffer не является саморазграничением, поэтому синтаксические анализаторы буфера протокола не могут самостоятельно определить, где заканчивается сообщение.Самый простой способ решить эту проблему - записать размер каждого сообщения перед тем, как написать само сообщение.Когда вы читаете сообщения обратно, вы читаете размер, затем читаете байты в отдельный буфер, а затем анализируете этот буфер.(Если вы хотите избежать копирования байтов в отдельный буфер, проверьте класс CodedInputStream (как на C ++, так и на Java), который может указывать ограничивать чтение определенным количеством байтов.)

6 голосов
/ 05 февраля 2012

Protobuf не включает терминатор для каждой внешней записи, поэтому вам нужно сделать это самостоятельно. Самый простой подход заключается в добавлении префикса к длине следующей записи. Лично я склонен использовать подход написания заголовка строки (для произвольного номера поля), а затем длины как «varint» - это означает, что весь документ сам по себе является действительным протобуфом и может использоваться как объект с «повторяющимся» элементом, однако, только маркер фиксированной длины (обычно 32-битный с прямым порядком байтов) будет работать так же хорошо. С любым таким хранилищем оно может быть добавлено по мере необходимости.

4 голосов
/ 16 января 2017

Если вы ищете решение C ++, Kenton Varda представила заплату для protobuf примерно в августе 2015 года , в которой добавлена ​​поддержка вызовов writeDelimitedTo () и readDelimitedFrom (), которые сериализуют / десериализуют последовательность протосообщения в / из файла способом, совместимым с Java-версией этих вызовов.К сожалению, этот патч еще не утвержден, поэтому, если вам нужна функциональность, вам нужно объединить его самостоятельно.

Другой вариант - Google имеет открытый код для чтения / записи файла protobuf через другие проекты.Например, библиотека or-tools содержит классы RecordReader и RecordWriter , которые сериализуют / десериализуют протопоток в файл.

Если вам нужны автономные версии этих классов, которые почти не имеют внешних зависимостей, у меня есть ветвь or-tools, которая содержит только эти классы.См .: https://github.com/moof2k/recordio

Чтение и запись с помощью этих классов просты:

File* file = File::Open("proto.log", "w");
RecordWriter writer(file);
writer.WriteProtocolMessage(msg1);
writer.WriteProtocolMessage(msg2);
...
writer.Close();
0 голосов
/ 14 июня 2012

Более простой способ - закодировать каждое сообщение в base64 и сохранить его в виде записи в строке.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...