Хранение набора сериализованных объектов protobuf

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

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

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

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

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

4

Решение

Предположим, ваш протобуф message выглядит так:

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

Затем в том же файле ввести еще 1 message которая является коллекцией этих Objects.

message Objects
{
repeated Object array = 1;
}

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

Кроме того, разумное использование Objects также позволит избежать создания дополнительных копий Object, Вы можете добавить элементы к этому и получить доступ, используя индексацию. repeated поля protobufs совместимы с 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;
}
}

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

3

Другие решения

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

1

По вопросам рекламы [email protected]