Подтвердить что ты не робот

Буферы протокола Google - сохранение сообщений в файл

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

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

4b9b3361

Ответ 1

Я бы рекомендовал использовать методы 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)

Ответ 2

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

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

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

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

Ответ 3

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

Ответ 4

Если вы ищете решение на С++, 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();

Ответ 5

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