2015-06-13 105 views
1

我试图使用Google Protocol Buffers从文件读取多个消息。文档suggests使用CodedInputStream使用协议缓冲区从文件读取消息的问题

但是,如果我尝试读取比一个非常小的信息,我从MergeFromCodedStream

例如获得一个失败者,如果我有一个消息定义为:

message Chunk { 
    repeated int64 values = 1 [packed=true]; 
} 

并尝试写留言到文件,然后读回:

int main() { 
    GOOGLE_PROTOBUF_VERIFY_VERSION; 
    { 
     Chunk chunk; 
     for (int i = 0; i != 26; ++i) 
     chunk.add_values(i); 

     std::ofstream output("D:\\temp.bin"); 
     OstreamOutputStream raw_output(&output); 

     if (!writeDelimitedTo(chunk, &raw_output)){ 
     std::cout << "Unable to write chunk\n"; 
     return 1; 
     } 
    } 
    { 
    std::ifstream input("D:\\temp.bin"); 
    IstreamInputStream raw_input(&input); 
    Chunk in_chunk; 

    if (!readDelimitedFrom(&raw_input, &in_chunk)) { // <--- Fails here 
     std::cout << "Unable to read chunk\n"; 
     return 1; 
    } 

    std::cout << "Num values in chunk " << in_chunk.values_size() << "\n"; 
    } 

    google::protobuf::ShutdownProtobufLibrary(); 
} 

,其中由非盟来自this answerwriteDelimitedToreadDelimitedFrom C++ protobuf库的thor:

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

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

    uint8_t* buffer = output.GetDirectBufferForNBytesAndAdvance(size); 
    if (buffer != NULL) { 
    message.SerializeWithCachedSizesToArray(buffer); 
    } else { 
    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); 

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

    google::protobuf::io::CodedInputStream::Limit limit = 
    input.PushLimit(size); 

    if (!message->MergeFromCodedStream(&input)) return false; // <-- Fails here 
    if (!input.ConsumedEntireMessage()) return false; 

    input.PopLimit(limit); 

    return true; 
} 

如果我只写25个值给我的消息,它的工作原理26,它失败。我已经展示了它在代码中失败的地方。

我试过调试到protobuf库,它似乎没有读取新的数据到缓冲区,但我不知道为什么。

我正在使用Visual Studio 2013和protobuf 2.6.1。

+0

你是说你改变了循环在的'主()',这样的限制是从'我改变了顶峰! = 26;'其他的东西比如'i!= 30;'你不能读出你添加的30个值?是否有'MergeFromCodedStream()'函数产生的错误代码?如果你在22条消息中写入更少的值,会发生什么?顺便说一下,我建议你修改你的两个函数'writeDelimitedTo()'和'readDelimitedFrom()'来返回一个特定的错误代码,它将指示函数失败的地方,而不是仅仅返回一个'bool'。 –

+0

@RichardChambers基本上,是的。如果我将循环更改为“i!= 25”,则按预期工作。正如所写的,'i!= 26'它失败了。据我所知,MergeFromCodedStream没有返回任何错误代码。只是一个表明成功或失败的布尔。 –

+2

你可能需要在'std :: ofstream'和'std :: ifstream'构造函数中添加'std :: ios :: binary'行结束标志。 – rhashimoto

回答

0

正如@rashimoto正确指出的,我无法以二进制模式打开我的文件!

随着该固定我可以成功地写入多个消息记录到文件:

int main() { 
    GOOGLE_PROTOBUF_VERIFY_VERSION; 
    { 
    std::vector<Chunk> chunks = createChunks(NUM_CHUNKS, CHUNK_SIZE); 

    std::ofstream output("D:\\temp.bin", std::ios::binary); 
    OstreamOutputStream raw_output(&output); 

    for (Chunk& chunk : chunks) { 
     if (!writeDelimitedTo(chunk, &raw_output)){ 
     std::cout << "Unable to write chunk\n"; 
     return 1; 
     } 
    } 
    } 
    { 
    std::ifstream input("D:\\temp.bin", std::ios::binary); 
    IstreamInputStream raw_input(&input); 
    std::vector<Chunk> chunks(NUM_CHUNKS); 

    for (auto& chunk : chunks) { 
     if (!readDelimitedFrom(&raw_input, &chunk)) { 
     std::cout << "Unable to read chunk\n"; 
     return 1; 
     } 
    } 

    std::cout << "Num values in first chunk " << chunks[0].values_size() << "\n"; 
    } 

    google::protobuf::ShutdownProtobufLibrary(); 
}