8

我在将 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 环境,带有协议缓冲区和 Qt 的 c++。

感谢您的时间!

4

3 回答 3

6

我通过从文件描述符切换到 fstream 并将 FileCopyStream 切换到 OstreamOutputStream 解决了这个问题。

尽管我已经看到使用前者的示例,但它对我不起作用。

我在 google coded_stream 标头中找到了一个很好的代码示例。链接#1

此外,由于我需要使用协议缓冲区将多条消息序列化到同一个文件,这个链接很有启发性。链接#2

出于某种原因,在我实际破坏流对象之前,输出文件并不“完整”。

于 2012-09-27T07:23:43.050 回答
3

读取失败是因为未使用 O_BINARY 打开文件进行读取 - 将文件打开更改为此并且它可以工作:

int fd = open("serializedMessage.pb", O_RDONLY | O_BINARY);

根本原因与此处相同:“ read() 仅从文件中读取几个字节”。您很可能遵循 protobuf 文档中的示例,该示例以相同的方式打开文件,但是当它遇到文件中的特殊字符时,它会在 Windows 上停止解析。

此外,在该库的更新版本中,您可以使用protobuf::util::ParseDelimitedFromCodedStream来简化读取大小+有效负载对。

...这个问题可能是古老的,但问题仍然存在,这个答案几乎可以肯定是对原始问题的修复。

于 2017-10-03T14:18:43.517 回答
-1

尝试使用

codedinput->readRawBytes而不是ReadString

dl.ParseFromArray代替ParseFromString

对协议缓冲区不太熟悉,但ReadString可能只读取 type 的字段strine

于 2012-09-25T12:37:55.273 回答