存储一组序列化的 protobuf 对象
Storing a set of serialized protobuf objects
我在我的 Protobuf 对象上使用 SerializeToString
,然后将字符串存储在数据库中。
但是,有时我有一组这样的对象。我想存储整个序列化数组,为此我需要在序列化字符串之间添加一些分隔符字符串。
据我所见documentation,该字符串只是一个字节数组,因此我没有得到关于其内容的任何承诺。
最好的方法是什么?
我不知道数组的长度,因为我们可能会在其中附加对象,我希望它在整个过程中都存储在数据库中。
如果您不能保证您的分隔符对于序列化数据的内容是唯一的,那么我会在每个对象的开头添加一个大小项,指示以下字符串的长度。
假设,你的 protobuf message
看起来像这样:
message Object
{
... = 1;
... = 2;
... = 3;
}
然后在同一个文件中再引入1个message
,这是这些Object
的集合。
message Objects
{
repeated Object array = 1;
}
因此,当您有很多元素时,您可以简单地使用 Objects
并在 Objects
本身上使用 SerializeAsString()
。这将节省您单独序列化单个 Object
并放置您自己的手工定界符的工作。您可以使用 Objects
.
的单个实例序列化所有 Object
s
使用这种方法,您 将所有解析和序列化工作也委托给 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;
}
}
以上只是一个例子。大家可以根据自己的项目需要关注。
我在我的 Protobuf 对象上使用 SerializeToString
,然后将字符串存储在数据库中。
但是,有时我有一组这样的对象。我想存储整个序列化数组,为此我需要在序列化字符串之间添加一些分隔符字符串。
据我所见documentation,该字符串只是一个字节数组,因此我没有得到关于其内容的任何承诺。
最好的方法是什么?
我不知道数组的长度,因为我们可能会在其中附加对象,我希望它在整个过程中都存储在数据库中。
如果您不能保证您的分隔符对于序列化数据的内容是唯一的,那么我会在每个对象的开头添加一个大小项,指示以下字符串的长度。
假设,你的 protobuf message
看起来像这样:
message Object
{
... = 1;
... = 2;
... = 3;
}
然后在同一个文件中再引入1个message
,这是这些Object
的集合。
message Objects
{
repeated Object array = 1;
}
因此,当您有很多元素时,您可以简单地使用 Objects
并在 Objects
本身上使用 SerializeAsString()
。这将节省您单独序列化单个 Object
并放置您自己的手工定界符的工作。您可以使用 Objects
.
的单个实例序列化所有 Object
s
使用这种方法,您 将所有解析和序列化工作也委托给 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;
}
}
以上只是一个例子。大家可以根据自己的项目需要关注。