2016-07-12 5 views
4

Я использую SerializeToString на моих объектах Protobuf, а затем сохраняю строку в БД.Хранение набора сериализованных объектов protobuf

Однако иногда у меня есть массив таких объектов. Я хотел бы сохранить весь сериализованный массив, и для этого мне нужна строка разделителя между сериализованными строками.

Согласно documentation, я видел, что строка представляет собой просто массив байтов, и поэтому я ничего не обещал мне в отношении ее содержимого.

Какой был бы лучший подход здесь?

Я не знаю длины массива, потому что объекты могут быть добавлены к нему, когда мы идем, и я хочу, чтобы он хранился в БД на протяжении всего процесса.

+1

Как насчет префикса потока строк с информацией о длине? – Arunmu

+0

Я мог бы префикс sizeof (int) перед каждой строкой. Похоже, он должен работать. Я попытаюсь опубликовать результаты, если будет работать – Mugen

ответ

3

Предположим, ваш Protobuf message выглядит следующим образом:

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

Затем в том же файле ввести более message 1, который представляет собой совокупность этих Object с.

message Objects 
{ 
    repeated Object array = 1; 
} 

Таким образом, если у вас есть много элементов, вы можете просто использовать Objects и использовать SerializeAsString() на самом Objects. Это позволит сэкономить ваши усилия на сериализацию отдельных Object отдельно и размещение собственного ограничителя ручной работы. Вы можете сериализовать все Object с использованием одного экземпляра Objects.
При таком подходе вы делегируете все разбор & сериализуете работу также в библиотеку Protobuf. Я использую это в своем проекте, и это работает как шарм.

Кроме того, разумное использование Objects также позволит избежать дополнительных копий Object. Вы можете добавлять элементы к ним и получать доступ с помощью индексации. Поле protobufs repeated совместимы с C++ 11, поэтому вы можете использовать его с итераторами или расширенным циклом for.


Важно отметить, что, когда вы сохраняете вывод Objects::SerializeAsString() в файл, вы должны первым вход длина этого string с последующим фактическим сериализованном строки. Во время чтения вы можете прочитать длину сначала, за которой следуют общие байты. Для простоты использования, я продлил std::fstream и перегружен ниже методы:

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; 
    } 
} 

Выше всего лишь иллюстрация. Вы можете следить в соответствии с потребностями вашего проекта.

+0

Хотя это красивое решение, было бы расточительно с точки зрения добавления сериализованных данных друг к другу. Мне пришлось бы десериализовать, добавить и пересоциализировать – Mugen

+0

@Mugen, нет никакой траты ресурсов, если вы не решите оставить 'Object' и 'Objects' отдельными.Более того, нет «добавления сериализованных данных», а просто «добавления данных». После этого вы можете сериализоваться только при хранении в файле или переходе в другую область. Аналогично десериализуем. Если вы найдете какую-то трату ресурсов, я бы предложил обновить здесь комментарий или ваш Q с соответствующим примером, чтобы я мог скрыть ваши сомнения. – iammilind

+2

@ Mugen На самом деле, из-за деталей формата protobuf, если вы объединяете два экземпляра 'Objects' (как определено выше), это в точности эквивалентно объединению повторяющегося поля' array' в один экземпляр и сериализации этого. Поэтому вам не нужно десериализовать, чтобы добавить! –

1

Если вы не можете гарантировать, что ваш разделитель будет уникальным для содержимого сериализованных данных, я бы добавил элемент размера в начале каждого объекта, указав, как долго будет следующая строка.

Смежные вопросы