Protocol Buffers es una API que usa Google internamente para codificar data. Podría parecerse a xml en que es data estructurada y multi-plataforma, pero es mucho más eficiente que éste, ya que la data va serializada. Sin embargo, a diferencia de la serialización propia de los lenguajes, define un protocolo común para todos los lenguajes. Éste es el aspecto que nos interesa, de hecho, ya que podría permitirnos comunicar data entre C++ y Java.

instalación C++

Descargamos el tarball desde acá >>, lo descomprimimos y dentro del directorio generado ejecutamos

./configure
make
make check
sudo make install

con lo que preparamos los makefiles, compilamos, corremos los tests e instalamos la librería compartida.

Nótese que en Linux (Debian y RedHat >> por lo menos) ejecutar el compilador protoc da el siguiente error

 protoc: error while loading shared libraries: libprotobuf.so.7: cannot open shared object file: No such file or directory

ésto se debe a que la librería compartida por defecto queda en /usr/local, el cual no está incluído en el LD_LIBRARY_PATH. En vez de cambiarlo, podemos ejecutar lo anterior con el siguiente flag

./configure --prefix=/usr

para que lo instale en /usr. (Si lo estamos ejecutando por segunda vez, hay que hacer antes un make clean)

.proto

Lo siguiente es definir la data que estaremos serializando. Ésto se hace con un archivo .proto. Aquí intentamos modelar una matriz para pasarla de un lenguaje a otro:

package mi.paquete; //namespace evita conflictos entre proyectos
option optimize_for = SPEED; //optimiza serialización
message Matrix{
repeated Vector vec = 1;
message Vector{
repeated double cell = 1 [packed=true]; //ineficiente sino
}
}

nótense las opciones packed=true, que es una optimización en la serialización de listas de primitivos, y SPEED, que optimiza el código generado para las opciones de serialización, lectura, etc. en detrimento del tamaño del código.

compilación

Finalmente para compilar este prototipo, usamos el comando protoc con la opción – -cpp_out para que nos genere los archivos C++

protoc --cpp_out=/ruta/salida matrix.proto

Ésto nos genera un header matrix.pb.h y una implementación matrix.pb.cpp.

Para ver qué es lo que contienen estos archivos, RTFM! >>

uso

Como dejé las clases dentro de mi proyecto, para poder usarlas

#include<matrix.pb.h>

estoy teniendo que poner mi workspace en el include path al compilador

-I"/mi/workspace/"

¿ésto estará bien?¿O en general se exportará a /usr/local?

Además, hay que poner la librería compartida en el linker con -lprotobuf

Para dar un ejemplo de cómo estoy llenando esta ‘matriz’, digamos que leo de un .csv los valores como en el siguiente pseudocódigo (el original es propietario…)

#include<matrix.pb.h>
//...
mi::paquete::Matrix matrix;

virtual void metodo(){
std::ifstream archivo;
archivo.open("/ruta/a/test.csv");
if(archivo.is_open()){
std::string linea;
while(archivo.good()){
std::getline(archivo, linea);

char *chars, *token;//csv
chars = new char[linea.size()+1];
strcpy (chars, linea.c_str());
token=strtok(chars,";");

//creo fila
mi::paquete::Matrix_Vector* vector = matrix.add_vec();
while (token!=NULL){
double numero;
std::istringstream buffer(token);
buffer >> numero;
vector->add_cell(numero);//creo celda
token=strtok(NULL,";");
}

delete[] chars;
}
archivo.close();
}
}

En seguida, puedo serializar este objeto en un binario como sigue

#include<fstream>
//...
std::fstream output("testprotobuff.bin", std::ios::out | std::ios::trunc | std::ios::binary);
matrix.SerializeToOstream(&output);

El cual luego podemos leer así

#include<fstream>
//...
std::fstream input("testprotobuff.bin", std::ios::in | std::ios::binary);
matrix.ParseFromIstream(&input);
Este sitio utiliza cookies.    Leer más