2015-06-13 40 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(); 
}