2012-09-25 20 views
6

Ho un problema con la memorizzazione dei dati di Protobuf su disco. L'applicazione che ho utilizza Protocol Buffer per trasferire dati su un socket (che funziona bene), ma quando provo a memorizzare i dati sul disco fallisce. In realtà, il salvataggio dei dati non presenta problemi, ma non riesco a caricarli di nuovo correttamente. Eventuali suggerimenti sarebbero graditi.Buffer di protocollo; salvataggio dei dati sul disco e caricamento del numero di aggiornamento

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); 
} 

Ho verificato i dati all'interno di questa funzione, il dLista contiene i dati che mi aspetto. I flussi segnalano che non si sono verificati errori e che una quantità ragionevole di byte è stata scritta sul disco. (anche il file è di dimensioni ragionevoli) Ma quando provo a rileggere i dati, non funziona. Inoltre, ciò che è veramente strano, è che se aggiungo più dati a questo file, posso leggere i primi messaggi (ma non quello alla fine).

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); 
} 

Ovviamente ho omesso parte del codice qui per semplificare tutto. Come nota a margine, ho anche provato a serializzare il messaggio su una stringa & salvando quella stringa tramite CodedOutputStream. Questo non funziona neanche. Ho verificato il contenuto di quella stringa, quindi suppongo che il colpevole debba essere la funzione di streaming.

Questo è un ambiente Windows, C++ con buffer di protocollo e Qt.

Grazie per il vostro tempo!

+0

Perché diavolo stai usando 'new' e chiama esplicitamente i distruttori? Questo non ha assolutamente senso. –

+0

Ho modificato per risolvere questo problema. Non ho idea del perché sia ​​sembrata una buona idea in quel momento. Buona cattura, ma non abbastanza per risolvere il mio problema. – almagest

+0

In realtà hai risolto solo metà problema: l'uso di puntatori e 'nuovo' qui non ha ancora senso. Ma sì, è improbabile che sia correlato al tuo problema. –

risposta

4

Ho risolto questo problema passando da descrittori di file a fstream e FileCopyStream a OstreamOutputStream.

Anche se ho visto esempi con il primo, non ha funzionato per me.

Ho trovato un buon esempio di codice nascosto nell'intestazione di google coded_stream. link #1

Inoltre, poiché avevo bisogno di serializzare più messaggi nello stesso file utilizzando i buffer del protocollo, questo collegamento era illuminante. link #2

Per qualche motivo, il file di output non è 'completo' fino a quando non decrescente gli oggetti del flusso.

-1

tenta di utilizzare

codedinput->readRawBytes INSEAD di ReadString

e

dl.ParseFromArray invece di ParseFromString

Non molto familiare con i buffer di protocollo, ma ReadString potrebbe solo leggere un campo di tipo strine.

+0

Buona idea , ma ha comportato lo stesso comportamento di prima. – almagest

2

L'errore di lettura è stato perché il file non è stato aperto per la lettura con O_BINARY - apertura file di modifica a questa e funziona:

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

La causa principale è lo stesso qui: "read() only reads a few bytes from file". Probabilmente stai seguendo un esempio nella documentazione di protobuf che apre il file nello stesso modo, ma smette di analizzare su Windows quando raggiunge un carattere speciale nel file.

Inoltre, nelle versioni più recenti della libreria, è possibile utilizzare protobuf::util::ParseDelimitedFromCodedStream per semplificare la lettura delle coppie formato + carico utile.

... la domanda potrebbe essere antica, ma il problema esiste ancora e questa risposta è quasi certamente la soluzione al problema originale.

Problemi correlati