Java中协议缓冲区分隔的I / O函数是否有C ++等价物?

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (24)

我试图从文件读取/写入多个Protocol Buffers消息,使用C ++和Java。谷歌建议在消息前写长度前缀,但默认情况下(我可以看到)没有办法做到这一点。

然而,版本2.1.0中的Java API收到了一组“分界”I / O函数,这些函数显然可以完成这项工作:

parseDelimitedFrom
mergeDelimitedFrom
writeDelimitedTo

是否有C ++等价物?如果不是,那么Java API附加的大小前缀的连线格式是什么,所以我可以用C ++解析这些消息?

提问于
用户回答回答于

我对这里的派对迟了一点,但下面的实现包含了其他答案中缺少的一些优化,并且在输入64MB后不会失败(尽管它仍然对每条消息实施了64MB的限制,而不是在整个流中)。

(我是C ++和Java protobuf库的作者,但是我不再为Google工作了,对不起,这段代码从未将它加入到官方的lib中,这就是它的样子。)

bool writeDelimitedTo(
    const google::protobuf::MessageLite& message,
    google::protobuf::io::ZeroCopyOutputStream* rawOutput) {
  // We create a new coded stream for each message.  Don't worry, this is fast.
  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) {
  // We create a new coded stream for each message.  Don't worry, this is fast,
  // and it makes sure the 64MB total size limit is imposed per-message rather
  // than on the whole stream.  (See the CodedInputStream interface for more
  // info on this limit.)
  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.
  google::protobuf::io::CodedInputStream::Limit limit =
      input.PushLimit(size);

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

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

  return true;
}
用户回答回答于

好的,所以我一直无法找到实现我所需的顶级C ++函数,但是通过Java API参考进行的一些探讨在MessageLite界面中发现了以下内容:

void writeDelimitedTo(OutputStream output)
/*  Like writeTo(OutputStream), but writes the size of 
    the message as a varint before writing the data.   */

所以Java大小前缀是一个(Protocol Buffers)varint!

掌握了这些信息后,我开始研究C ++ API并发现了CodedStream标头,它包含以下内容:

bool CodedInputStream::ReadVarint32(uint32 * value)
void CodedOutputStream::WriteVarint32(uint32 value)

使用这些,我应该能够推出自己的C ++函数来完成这项工作。

他们应该真的把它添加到主要的消息API,但是; 它考虑到Java的缺失功能,Marc Gravell的优秀protobuf-net C#端口(通过SerializeWithLengthPrefix和DeserializeWithLengthPrefix)也是如此。

扫码关注云+社区