我正在尝试从C++和Java文件中读/写多个协议缓冲区消息。谷歌建议在消息前写上长度前缀,但默认情况下没有办法(我看得出来)。
然而,版本2.1.0中的Java API接收了一组“分隔的”I/O函数,它们显然完成了这项工作:
parseDelimitedFrom
mergeDelimitedFrom
writeDelimitedTo
是否有C++等效项?如果不是,Java API附加的大小前缀的有线格式是什么,以便我可以在C++中解析这些消息?
更新:
从v3.3.0开始,这些都存在于google/protobuf/util/delimited_message_util.h
中。
发布于 2014-04-08 11:49:06
我在这里有点晚了,但是下面的实现包含了其他答案中缺少的一些优化,并且在64MB的输入之后不会失败(尽管它仍然在每个单独的消息上强制执行the 64MB limit,只是不是在整个流上)。
(我是C++和Java protobuf库的作者,但我不再为谷歌工作。很抱歉,这段代码没有进入官方的库中。这就是如果它是这样的话会是什么样子。)
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;
}
发布于 2010-02-26 20:53:21
好吧,我还没能找到实现我所需要的顶级C++函数,但是在MessageLite接口内部,通过Java API参考发现了以下内容:
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标头,其中包含以下内容:
bool CodedInputStream::ReadVarint32(uint32 * value)
void CodedOutputStream::WriteVarint32(uint32 value)
使用这些,我应该能够使用我自己的C++函数来完成这项工作。
不过,他们真的应该把它添加到主Message API中;考虑到Java有它,它缺少功能,Marc Gravell优秀的protobuf-net C#端口(通过SerializeWithLengthPrefix和DeserializeWithLengthPrefix)也是如此。
发布于 2010-02-26 21:19:02
我解决了同样的问题,使用CodedOutputStream/ArrayOutputStream写入消息(大小),使用CodedInputStream/ArrayInputStream读取消息(大小)。
例如,下面的伪代码将消息大小写在消息后面:
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提供的方便方法,那肯定会很方便。
https://stackoverflow.com/questions/2340730
复制相似问题