msgpack(messagepack)是一种类似json的二进制序列化格式,可以将多种编程语言的数据转换为二进制序列,用以存储或实现不同语言之间的交换。相较于json,其序列化时更加快速、高效,更加节省空间,对于大量数据的存储(如numpy数组)具有较大优势。
最近在使用这个工具时遇到一个大坑,费了些周折,特此记录。
问题描述:从网上下载了一个数据集特征文件(lmdb文件),需要从中读取经msgpack序列化的数据。用lmdb获取到文件内容之后,我使用msgpack进行解码,解码结果为一个python字典(一开始并不知道存储的数据是什么格式),但是其中的部分键和值出现乱码,具体如下:
其中部分值显示正常,部分值是bytes形式:b’xxx’。
一开始我以为是编码格式的问题,于是尝试手动将二进制形式的值用各种格式解码,例如:gbk, ISO-8859-1等,发现无法正常解码。
后续查阅资料过程中,发现还有一个叫做msgpack-numpy的模块,简单查看了这个模块的介绍,发现它就是解决以上问题的答案。msgpack-numpy模块功能十分简单,只是作为msgpack的一个辅助模块,官方介绍如下(github主页):
This package provides encoding and decoding routines that enable the
serialization and deserialization of numerical and array data types
provided by numpy using the highly efficient msgpack format.
Serialization of Python’s native complex data types is also supported.
莫非我要打开的文件是序列化之后的numpy数组?于是我按照msgpack-numpy的官网介绍,安装了此模块,并在我的代码开头添加了以下两行:
import msgpack_numpy
msgpack_numpy.patch()
之后运行之前的代码,居然成功解析出了结果:
原来文件里的内容是一个只有单键值对的字典,其中唯一的值为一个numpy array!而msgpack默认是不能直接编码和解码numpy array的!需要配合msgpack-numpy一起使用。
使用方式主要有两种,一种就是以上我采用的方式,在调用msgpack之前import msgpack-numpy模块,并添加一下代码:
msgpack_numpy.patch()
另一种方式是在使用msgpack进行编码或解码的时候,手动传入msgpack-numpy提供的编/解码器,官方示例如下:
import msgpack
import msgpack_numpy as m
import numpy as np
x = np.random.rand(5)
x_enc = msgpack.packb(x, default=m.encode)
x_rec = msgpack.unpackb(x_enc, object_hook=m.decode)
题外话:msgpack-numpy模块本身功能较为简单,建议整合进msgpack模块。目前msgpack的相关文档里都没看到关于msgpack-numpy的介绍,使用者较难了解到这一辅助模块及其用法,容易踩坑。