简体   繁体   English

协议缓冲区:如何将多个消息序列化和反序列化为文件(c ++)?

[英]protocol buffers: how to serialize and deserialize multiple messages into a file (c++)?

I am new to Protocol Buffers and c++ but my task requires me to use the two. 我是Protocol Buffers和c ++的新手,但我的任务要求我使用这两个。 I want to write a structure of data ( message) into a single file multiple times and be able to read the data. 我想多次将数据结构(消息)写入单个文件,并能够读取数据。 i can read and write a single message but multiple messages is proving harder. 我可以读取和写入一条消息,但多条消息证明更难。 I have looked for answers for hours but i can't seem to be able to read the data as a structure. 我已经找了几个小时的答案,但我似乎无法将数据作为结构读取。 Any example code or pointers will be very helpful. 任何示例代码或指针都非常有用。

This is the format of my structure: 这是我的结构格式:

    typedef struct Entry
       {
          char  name[ NAME_MAX];
          int   id;
          int   age;
          char  DoB[32]; 
       } entry;

This is what i've been using to write into a file: 这就是我用来写入文件的内容:

    Person_File file;
    fstream output("file", ios::out | ios::trunc | ios::binary);
    file.SerializeToOstream(&output);

I have tried to change the file editing options to append instead of truncate but that does not let me read the data in the format that I want. 我试图更改文件编辑选项以追加而不是截断,但这不允许我以我想要的格式读取数据。

this is what I use to read: 这是我用来阅读的内容:

    fstream input("file", ios::in | ios::binary);
    file.ParseFromIstream(&input);

These are the contents of my .proto file: 这些是我的.proto文件的内容:

    message Person {


message File {
    required string pname =1;
    required int32 id =2;
    required int32 age =3;
    required string DoB =4;
}

repeated File file =1;

} }

From all the searching i've done it seems like CodedInputStream/CodedOutputStream are my best options but I haven't been able to find any detailed examples or explanation to help me understand. 从我所做的所有搜索看来,CodedInputStream / CodedOutputStream似乎是我最好的选择,但我找不到任何详细的例子或解释来帮助我理解。 I understand that Protocol Buffers are not self delimiting and this is probably the reason why I can't read my messages back in the original format. 我知道协议缓冲区不是自我划分的,这可能是我无法以原始格式读回我的消息的原因。 Any help would be appreciated. 任何帮助,将不胜感激。 Thanks 谢谢

EDIT: I have tried to use CodedOutputStream based on the messages I've recieved but it doesn't seem to write anything into the file. 编辑:我已经尝试使用CodedOutputStream基于我收到的消息但它似乎没有写入任何文件。

    int fd = open("file.txt",O_WRONLY | O_APPEND | O_CREAT);

    FileOutputStream* file_ostream_ = new FileOutputStream(fd);
    CodedOutputStream* ostream_ = new CodedOutputStream(file_ostream_);


ostream_->WriteLittleEndian32(file.ByteSize());
    file.SerializeToCodedStream(ostream_);

After using this code the file comes out blank. 使用此代码后,该文件显示为空白。 Where am I going wrong ? 我哪里错了?

I have tried to use CodedOutputStream based on the messages I've recieved but it doesn't seem to write anything into the file. 我已经尝试使用基于我收到的消息的CodedOutputStream但它似乎没有在文件中写入任何内容。

I suspect your problem here is that you aren't deleting the CodedOutputStream nor the FileOutputStream . 我怀疑你的问题是你没有删除CodedOutputStreamFileOutputStream These objects buffer output and flush the buffer in their destructors, so if you never destroy them, they won't write the last buffer, which in this case is the only buffer. 这些对象缓冲输出并在其析构函数中刷新缓冲区,因此如果您永远不会销毁它们,它们将不会写入最后一个缓冲区,在这种情况下它是唯一的缓冲区。

I recommend allocating these objects on the stack (as local variables). 我建议在堆栈上分配这些对象(作为局部变量)。 Then you can't possibly forget to destroy them. 然后你不可能忘记摧毁它们。

With that out of the way, here's code that uses CodedInputStream and CodedOutputStream to read/write delimited messages. 有了这个,这里的代码使用CodedInputStreamCodedOutputStream来读/写分隔的消息。 Each message is prefixed with a varint indicating the size, which is the same format as the Java Protobuf library's writeDelimitedTo() / parseDelimitedFrom() (a feature that never made it into the C++ library). 每条消息的前缀都是一个指示大小的varint,其格式与Java Protobuf库的writeDelimitedTo() / parseDelimitedFrom() (一种从未进入C ++库的特性)相同。

bool writeDelimitedTo(
    const google::protobuf::MessageLite& message,
    google::protobuf::io::ZeroCopyOutputStream* rawOutput) {
  google::protobuf::io::CodedOutputStream output(rawOutput);

  // Write the size.
  const int size = message.ByteSize();
  output.WriteVarint32(size);

  uint8_t* buffer = output.GetDirectBufferForNBytesAndAdvance(size);
  if (buffer != NULL) {
    // Optimization:  The message fits in one buffer, so use the faster
    // direct-to-array serialization path.
    message.SerializeWithCachedSizesToArray(buffer);
  } else {
    // Slightly-slower path when the message is multiple buffers.
    message.SerializeWithCachedSizes(&output);
    if (output.HadError()) return false;
  }

  return true;
}

bool readDelimitedFrom(
    google::protobuf::io::ZeroCopyInputStream* rawInput,
    google::protobuf::MessageLite* message) {
  google::protobuf::io::CodedInputStream input(rawInput);

  // Read the size.
  uint32_t size;
  if (!input.ReadVarint32(&size)) return false;

  // Tell the stream not to read beyond that size.
  auto limit = input.PushLimit(size);

  // Parse the message.
  if (!message->MergePartialFromCodedStream(&input)) return false;
  if (!input.ConsumedEntireMessage()) return false;

  // Release the limit.
  input.PopLimit(limit);

  return true;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM