我将Protobuf数据存储到磁盘时遇到问题。 我使用协议缓冲区通过套接字传输数据的应用程序(工作正常),但当我尝试将数据存储到磁盘时它失败。 实际上,保存数据报告没有问题,但我似乎无法再次正确加载它们。 任何提示都会很高兴。
void writeToDisk(DataList & dList)
{
// open streams
int fd = open("serializedMessage.pb", O_WRONLY | O_CREAT);
google::protobuf::io::ZeroCopyOutputStream* fileOutput = new google::protobuf::io::FileOutputStream(fd);
google::protobuf::io::CodedOutputStream* codedOutput = new google::protobuf::io::CodedOutputStream(fileOutput);
// save data
codedOutput->WriteLittleEndian32(PROTOBUF_MESSAGE_ID_NUMBER); // store with message id
codedOutput->WriteLittleEndian32(dList.ByteSize()); // the size of the data i will serialize
dList.SerializeToCodedStream(codedOutput); // serialize the data
// close streams
delete codedOutput;
delete fileOutput;
close(fd);
}
我已验证此函数内的数据,dList包含我期望的数据。流报告没有发生错误,并且将合理数量的字节写入磁盘。 (文件大小合理) 但是当我尝试回读数据时,它不起作用。而且,真正奇怪的是,如果我将更多数据附加到此文件,我可以读取第一条消息(但不是最后的消息)。
void readDataFromFile()
{
// open streams
int fd = open("serializedMessage.pb", O_RDONLY);
google::protobuf::io::ZeroCopyInputStream* fileinput = new google::protobuf::io::FileInputStream(fd);
google::protobuf::io::CodedInputStream* codedinput = new google::protobuf::io::CodedInputStream(fileinput);
// read back
uint32_t sizeToRead = 0, magicNumber = 0;
string parsedStr = "";
codedinput->ReadLittleEndian32(&magicNumber); // the message id-number i expect
codedinput->ReadLittleEndian32(&sizeToRead); // the reported data size, also what i expect
codedinput->ReadString(&parsedstr, sizeToRead)) // the size() of 'parsedstr' is much less than it should (sizeToRead)
DataList dl = DataList();
if (dl.ParseFromString(parsedstr)) // fails
{
// work with data if all okay
}
// close streams
delete codedinput;
delete fileinput;
close(fd);
}
显然我在这里省略了一些代码来简化一切。 作为旁注,我也尝试将消息序列化为字符串&通过CodedOutputStream保存该字符串。这也不起作用。我已经验证了该字符串的内容,所以我猜罪魁祸首必须是流函数。
这是一个Windows环境,带有协议缓冲区的c ++和Qt。
感谢您的时间!
答案 0 :(得分:6)
我通过从文件描述符切换到fstream,将FileCopyStream切换到OstreamOutputStream解决了这个问题。
虽然我看过使用前者的例子,但它对我不起作用。
我在google coded_stream标头中找到了一个很好的代码示例。 link #1
此外,由于我需要使用协议缓冲区将多个消息序列化到同一个文件,因此这个链接很有启发性。 link #2
出于某种原因,在我实际解析流对象之前,输出文件不是“完整”。
答案 1 :(得分:2)
读取失败是因为没有打开文件以便使用O_BINARY进行读取 - 将文件更改为打开并且它可以正常工作:
int fd = open("serializedMessage.pb", O_RDONLY | O_BINARY);
根本原因与此处相同:" read() only reads a few bytes from file"。您很可能在protobuf文档中按照相同的方式打开文件中的示例,但它会在Windows上遇到文件中的特殊字符时停止解析。
此外,在更新版本的库中,您可以使用protobuf::util::ParseDelimitedFromCodedStream
来简化读取大小+有效负载对。
......问题可能很古老,但问题仍然存在,这个答案几乎肯定是对原始问题的解决方法。
答案 2 :(得分:-1)
尝试使用
codedinput->readRawBytes
代替ReadString
和
dl.ParseFromArray
代替ParseFromString
不熟悉协议缓冲区,但ReadString
可能只读取strine
类型的字段。