Ha pasado mucho tiempo desde el artículo anterior donde expliqué cómo compilar protobuf con soporte de zlib. En este artículo explicaré cómo usar flujos (streams) de C++ basados en zlib para serializar y deserealizar mensajes Protobuf. Usaremos un pequeño bitmap de la Mona Lisa para este ejemplo, ya que su formato descomprimido compactará muy bien con el algoritmo Deflate usado por zlib.

Echa un vistazo a Simverge/howto-protobuf-zlib en GitHub para una implementación más completa de este ejemplo.

Define un esquema de mensaje Protobuf

Primero, creemos un archivo llamado blob.proto que defina un simple mensaje Protobuf que almacene una collección arbitraria de datos además de una cadena de texto que identifique su origen:

Compila blob.proto con el compilador de Protobuf (protoc) usando las instrucciones del tutorial oficial de Protobuf en C++. Por ejemplo, el siguiente comando generaría el archivo fuente para C++ llamado blob.pb.cc y la cabecera para C++ llamada blob.pb.h en el mismo directorio dónde reside blob.proto:

Otra opción es usar el módulo FindProtobuf si compilas con CMake, por ejemplo:

Cuando blob.proto es compilado a archivos de C++ y blob.pb.cc es incluído en la compilación, puedes incluír la cabecera blob.pb.h para crear un mensaje Protobuf de tipo simverge::Blob, definir sus campos de origen y datos, y determinar el tamaño del mensaje Protobuf descomprimido:

Al ejecutar este programa vemos el tamaño del bitmap de la Mona Lisa y del mensaje Protobuf que lo envuelve:

Comprime y escribe el mensaje Protobuf al disco

Podemos luego usar un flujo de salida del tipo GzipOutputStream definido en el espacio de nombres (namespace) google::protobuf::io para serializar y comprimir el mensaje. El constructor de esta clase requiere un puntero a un subflujo de tipo  ZeroCopyOutputStream para procesar los datos comprimidos. Usaremos un objeto ArrayOutputStream para determinar el tamaño de los datos comprimidos y después un objeto std::ofstream para escribir el arreglo de bytes al disco. También confirmaremos que no hayan errores de zlib anted de escribir el mensaje Protobuf comprimido al disco:

Al ejecutar este programa vemos que la configuración por defecto de GzipOutputStream brinda una tasa de compresión de aproximadamente 22.6% con el bitmap de la Mona Lisa. Puedes ajustar la configuración de compresión con zlib pasando un objeto de tipo GzipOutputStream::Options al constructor de GzipOutputStream.

Una forma más sencilla de serializar los datos comprimidos es usar como subflujo de salida un objeto de tipo OstreamOutputStream o FileOutputStream en vez de ArrayOutputStream.

Lee y descomprime el mensaje Protobuf

Usemos un flujo de entrada de tipo GzipInputStream definido en google::protobuf::io para leer y descomprimir el mensaje. El constructor de esta clase requiere un puntero a un subflujo de tipo ZeroCopyInputStream para leer los datos antes de la descompresión. Usaremos un objeto de tipo IstreamInputStream como subflujo (el cual requiere un puntero a un flujo de entrada de tipo std::istream) en contraste al subflujo basado en un arreglo de bytes que usamos en el ejemplo de salida. Tal cómo hicimos en el ejemplo de salida, revisaremos si hay errores de zlib antes de procesar los datos descomprimidos.

Al ejecutar este programa vemos que el mensaje Protobuf descomprimido y analizado desde el archivo corresponde al que fue creado por el ejemplo de salida, además de corresponder el tamaño de los datos con el del archivo bitmap.

Licencia Creative Commons
Esta obra de Simverge Software LLC está bajo una Licencia Creative Commons Atribución 4.0 Internacional.

0 0 votes
Article Rating
Subscribe
Notify of
guest
0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments