2012-09-25 46 views
6

我在將Protobuf數據存儲到磁盤時遇到問題。 我使用協議緩衝區通過套接字傳輸數據的應用程序(工作正常),但是當我嘗試將數據存儲到磁盤時失敗。 其實,保存數據報告沒有問題,但我似乎無法正常加載它們。 任何提示將很樂意欣賞。Protocol Buffers;將數據保存到磁盤並加載返回問題

void writeToDisk(DataList & dList) 
{ 
    // open streams 
    int fd = open("serializedMessage.pb", O_WRONLY | O_CREAT); 
    google::protobuf::io::ZeroCopyOutputStream* fileOutput = new google::protobuf::io::FileOutputStream(fd); 
    google::protobuf::io::CodedOutputStream* codedOutput = new google::protobuf::io::CodedOutputStream(fileOutput); 

    // save data 
    codedOutput->WriteLittleEndian32(PROTOBUF_MESSAGE_ID_NUMBER); // store with message id 
    codedOutput->WriteLittleEndian32(dList.ByteSize()); // the size of the data i will serialize 
    dList.SerializeToCodedStream(codedOutput); // serialize the data 

    // close streams 
    delete codedOutput; 
    delete fileOutput; 

    close(fd); 
} 

我已驗證此函數中的數據,dList包含我期望的數據。這些流報告沒有發生錯誤,並且合理的字節數被寫入磁盤。 (該文件也是合理的大小) 但是當我嘗試讀回數據時,它不起作用。此外,真正奇怪的是,如果我向這個文件添加更多數據,我可以讀取第一條消息(但不是最後一條消息)。

void readDataFromFile() 
{ 
    // open streams 
    int fd = open("serializedMessage.pb", O_RDONLY); 
    google::protobuf::io::ZeroCopyInputStream* fileinput = new google::protobuf::io::FileInputStream(fd); 
    google::protobuf::io::CodedInputStream* codedinput = new google::protobuf::io::CodedInputStream(fileinput); 

    // read back 
    uint32_t sizeToRead = 0, magicNumber = 0; 
    string parsedStr = ""; 

    codedinput->ReadLittleEndian32(&magicNumber); // the message id-number i expect 
    codedinput->ReadLittleEndian32(&sizeToRead); // the reported data size, also what i expect 
    codedinput->ReadString(&parsedstr, sizeToRead)) // the size() of 'parsedstr' is much less than it should (sizeToRead) 

    DataList dl = DataList(); 

    if (dl.ParseFromString(parsedstr)) // fails 
    { 
     // work with data if all okay 
    } 

    // close streams 
    delete codedinput; 
    delete fileinput; 
    close(fd); 
} 

很明顯我省略了一些代碼來簡化一切。 作爲一個側面說明,我也試圖將該消息序列化爲一個字符串&,通過CodedOutputStream保存該字符串。這也不起作用。我已經驗證了該字符串的內容,所以我想罪魁禍首必須是流功能。

這是一個Windows環境,帶有協議緩衝區和Qt的C++。

謝謝你的時間!

+0

爲什麼你在使用'new'並顯式調用析構函數?這沒有任何意義。 –

+0

我已編輯修復此問題。我不知道爲什麼當時這似乎是個好主意。好的發現,但還不足以解決我的問題。 – almagest

+0

你實際上只修復了一半問題:在這裏使用指針和'new'仍然沒有意義。但是,是的,這不太可能與你的問題有關。 –

回答

4

我從文件描述符切換到fstream的解決了這個問題,並FileCopyStream到OstreamOutputStream。

雖然我看過使用前者的例子,但它並不適合我。

我在隱藏在google coded_stream頭文件中發現了一個很好的代碼示例。 link #1

另外,由於我需要序列的多個消息到使用協議緩衝區相同的文件,該鏈接是啓發。 link #2

出於某種原因,輸出文件是不是「完整的」,直到我真正desctruct流對象。

-1

嘗試使用ReadString

codedinput->readRawBytes INSEAD和

dl.ParseFromArray代替ParseFromString

不是很熟悉協議緩存,但ReadString可能只讀strine類型的字段。

+0

不必要地使用'new'和'delete'好主意,但它導致了和以前一樣的行爲。 – almagest

2

讀取失敗是因爲文件不與O_BINARY閱讀打開 - 改變文件打開這個和它的作品:

int fd = open("serializedMessage.pb", O_RDONLY | O_BINARY);

的根本原因是一樣的位置:「read() only reads a few bytes from file」。您很可能會在protobuf文檔中以相同的方式打開該文件,但當它在文件中遇到特殊字符時會停止在Windows上解析。

此外,在更新版本的庫中,您可以使用protobuf::util::ParseDelimitedFromCodedStream來簡化讀取大小+有效負載對。

...這個問題可能很古老,但問題仍然存在,這個答案几乎肯定是對原始問題的修復。