协议缓冲区;将数据保存到磁盘&加载问题

时间:2012-09-25 10:50:38

标签: c++ protocol-buffers

我将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。

感谢您的时间!

3 个答案:

答案 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类型的字段。