首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >在Java语言中,协议缓冲区分隔的I/O函数是否有C++等效项?

在Java语言中,协议缓冲区分隔的I/O函数是否有C++等效项?
EN

Stack Overflow用户
提问于 2010-02-26 17:58:27
回答 9查看 30.2K关注 0票数 67

我正在尝试从C++和Java文件中读/写多个协议缓冲区消息。谷歌建议在消息前写上长度前缀,但默认情况下没有办法(我看得出来)。

然而,版本2.1.0中的Java API接收了一组“分隔的”I/O函数,它们显然完成了这项工作:

代码语言:javascript
复制
parseDelimitedFrom
mergeDelimitedFrom
writeDelimitedTo

是否有C++等效项?如果不是,Java API附加的大小前缀的有线格式是什么,以便我可以在C++中解析这些消息?

更新:

从v3.3.0开始,这些都存在于google/protobuf/util/delimited_message_util.h中。

EN

回答 9

Stack Overflow用户

回答已采纳

发布于 2014-04-08 11:49:06

我在这里有点晚了,但是下面的实现包含了其他答案中缺少的一些优化,并且在64MB的输入之后不会失败(尽管它仍然在每个单独的消息上强制执行the 64MB limit,只是不是在整个流上)。

(我是C++和Java protobuf库的作者,但我不再为谷歌工作。很抱歉,这段代码没有进入官方的库中。这就是如果它是这样的话会是什么样子。)

代码语言:javascript
复制
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;
}
票数 81
EN

Stack Overflow用户

发布于 2010-02-26 20:53:21

好吧,我还没能找到实现我所需要的顶级C++函数,但是在MessageLite接口内部,通过Java API参考发现了以下内容:

代码语言:javascript
复制
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++应用程序接口,找到了CodedStream标头,其中包含以下内容:

代码语言:javascript
复制
bool CodedInputStream::ReadVarint32(uint32 * value)
void CodedOutputStream::WriteVarint32(uint32 value)

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

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

票数 17
EN

Stack Overflow用户

发布于 2010-02-26 21:19:02

我解决了同样的问题,使用CodedOutputStream/ArrayOutputStream写入消息(大小),使用CodedInputStream/ArrayInputStream读取消息(大小)。

例如,下面的伪代码将消息大小写在消息后面:

代码语言:javascript
复制
const unsigned bufLength = 256;
unsigned char buffer[bufLength];
Message protoMessage;

google::protobuf::io::ArrayOutputStream arrayOutput(buffer, bufLength);
google::protobuf::io::CodedOutputStream codedOutput(&arrayOutput);

codedOutput.WriteLittleEndian32(protoMessage.ByteSize());
protoMessage.SerializeToCodedStream(&codedOutput);

在编写时,您还应该检查您的缓冲区是否足够大,以容纳消息(包括大小)。在阅读时,您应该检查您的缓冲区是否包含完整的消息(包括大小)。

如果他们在C++ API中添加类似于Java API提供的方便方法,那肯定会很方便。

票数 12
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/2340730

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档