2012-09-25 9 views
6

Tengo un problema con el almacenamiento de datos de Protobuf en el disco. La aplicación que tengo usa Protocol Buffer para transferir datos a través de un socket (que funciona bien), pero cuando intento almacenar los datos en el disco, falla. En realidad, el guardado de datos informa que no hay problemas, pero parece que no puedo volver a cargarlos correctamente. Cualquier consejo sería apreciado gustosamente.Buffers de protocolo; guardar datos en el disco y cargar el número de vuelta

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

He verificado los datos dentro de esta función, la dList contiene los datos que espero. Las secuencias informan que no se producen errores y que se escribieron una cantidad razonable de bytes en el disco. (también el archivo es de tamaño razonable) Pero cuando trato de leer los datos, no funciona. Además, lo que es realmente extraño, es que si agrego más datos a este archivo, puedo leer los primeros mensajes (pero no el que está al final).

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

Obviamente he omitido parte del código aquí para simplificarlo todo. Como nota al margen, también he intentado serializar el mensaje en una cadena &, guardar esa cadena a través de CodedOutputStream. Esto tampoco funciona. Aunque he verificado el contenido de esa cadena, así que supongo que las funciones de transmisión deben ser culpables.

Este es un entorno de Windows, C++ con búferes de protocolo y Qt.

¡Gracias por su tiempo!

+0

¿Por qué diablos estás usando 'new' y llamando explícitamente a los destructores? Eso no tiene ningún sentido en absoluto. –

+0

He corregido para solucionar este problema. No tengo idea de por qué parecía una buena idea en ese momento. Buena captura, pero no lo suficiente como para solucionar mi problema. – almagest

+0

En realidad, solo resolvió la mitad del problema: usar punteros y 'nuevo' aquí todavía no tiene sentido. Pero sí, es poco probable que esté relacionado con tu problema. –

Respuesta

4

He resuelto este problema al cambiar de los descriptores de archivo a fstream, y FileCopyStream a OstreamOutputStream.

Aunque he visto ejemplos usando el primero, no funcionó para mí.

Encontré un bonito ejemplo de código oculto en el encabezado google coded_stream. link #1

Además, dado que necesitaba serializar varios mensajes en el mismo archivo utilizando búferes de protocolo, este enlace fue esclarecedor. link #2

Por alguna razón, el archivo de salida no está "completo" hasta que realmente desctruct los objetos de secuencia.

-1

tratan de utilizar

codedinput->readRawBytes insead de ReadString

y

dl.ParseFromArray en lugar de ParseFromString

No muy familiarizado con tampones de protocolo, pero ReadString solamente podría leer un campo de tipo strine.

+0

Buena idea , pero resultó en el mismo comportamiento que antes. – almagest

2

El fallo de lectura se debía a que el archivo no se abrió a la lectura con O_BINARY - cambio de la apertura de archivos para esto y funciona:

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

La raíz del problema es el mismo que aquí: "read() only reads a few bytes from file". Es muy probable que siga un ejemplo en la documentación de protobuf que abre el archivo de la misma manera, pero deja de analizar en Windows cuando golpea un carácter especial en el archivo.

Además, en las versiones más recientes de la biblioteca, puede usar protobuf::util::ParseDelimitedFromCodedStream para simplificar el tamaño de lectura + pares de carga útil.

... la pregunta puede ser antigua, pero el problema persiste y esta respuesta es casi seguramente la solución al problema original.

Cuestiones relacionadas