【问题标题】:Protocol Buffers; saving data to disk & loading back issue协议缓冲区;将数据保存到磁盘并加载回问题
【发布时间】:2012-09-25 10:50:38
【问题描述】:

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

感谢您的宝贵时间!

【问题讨论】:

  • 你到底为什么要使用new 并显式调用析构函数?这没有任何意义。
  • 我已编辑以解决此问题。我不知道为什么这在当时看起来是个好主意。很好,但不足以解决我的问题。
  • 您实际上只解决了一半问题:在这里使用指针和new 仍然没有意义。但是,是的,这不太可能与您的问题有关。
  • 他可能通过查看CodedOutputStream 示例developers.google.com/protocol-buffers/docs/reference/cpp/… 不必要地使用了newdelete

标签: c++ protocol-buffers


【解决方案1】:

读取失败是因为未使用 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】:

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

    虽然我见过使用前者的例子,但它对我不起作用。

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

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

    由于某种原因,在我真正解构流对象之前,输出文件并不“完整”。

    【讨论】:

      【解决方案3】:

      尝试使用

      codedinput->readRawBytes insead of ReadString

      dl.ParseFromArray 而不是ParseFromString

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

      【讨论】:

      • 好主意,但结果与以前相同。
      猜你喜欢
      • 1970-01-01
      • 2019-07-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-12-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多