为什么协议缓冲区c ++库没有正确读取二进制对象

时间:2011-12-09 05:04:47

标签: visual-c++ serialization protocol-buffers

我使用协议缓冲区使用c ++程序创建了一个二进制文件。我在C#程序中读取二进制文件时遇到了问题,所以我决定编写一个小的c ++程序来测试读数。

我的原型文件如下

message TradeMessage {
required double timestamp = 1;
required string ric_code = 2;
required double price = 3;
required int64 size = 4;
required int64 AccumulatedVolume = 5;
} 

写入协议缓冲区时,我先写对象类型,然后是对象长度和对象本身。

coded_output->WriteLittleEndian32((int) ObjectType_Trade); 
coded_output->WriteLittleEndian32(trade.ByteSize()); 
trade.SerializeToCodedStream(coded_output);

现在,当我尝试在我的c ++程序中读取相同的文件时,我看到了奇怪的行为。

我的阅读代码如下:

coded_input->ReadLittleEndian32(&objtype);
coded_input->ReadLittleEndian32(&objlen);
tMsg.ParseFromCodedStream(coded_input);
cout << "Expected Size = " << objlen << endl;
cout<<" Trade message received for: "<< tMsg.ric_code() << endl;
cout << "TradeMessage Size = " << tMsg.ByteSize() << endl;

在这种情况下,我得到以下输出

Expected Size = 33
Trade message received for: .CSAP0104
TradeMessage Size = 42

当我写入文件时,我将trade.ByteSize()写为33个字节,但是当我读取同一个对象时,对象ByteSize()是42个字节,这会影响其余的数据。我不确定这有什么问题。请指教。

此致 阿洛克

2 个答案:

答案 0 :(得分:1)

根据上述情况,这是猜测:当您使用ParseFromCodedStream时,实际上并没有将其限制为您之前找到的objlen;因此,如果流包含的数据多于此数据(即不是文件的末尾),则引擎将尝试继续读取EOF。你必须根据你的期望限制长度。我不是C ++专家,所以我不能提供直接指导,但如果这是C#(使用protobuf-net):

objType = ProtoReader.DirectReadLittleEndianInt32(file);
len = ProtoReader.DirectReadLittleEndianInt32(file);

// assume GetObjectType returns typeof(TradeMessage) for our objType
Type type = GetObjectType(objType);
msg = RuntimeTypeModel.Default.Deserialize(file, null, type, len, null);

答案 1 :(得分:1)

显然,我在创建二进制文件时犯了一个非常愚蠢的错误。当我向它写入protobuf数据时,我没有以二进制模式打开文件,导致它在中间添加奇怪的ascii字符。这在使用protobuf-net库读取数据时引起了问题。这个问题在这里解决了。不应该花这么长时间来解决这个问题。