numpy.array与base64互转为何需使用np.frombuffer及相关问题
import base64 import numpy as np array = np.array([1,2]).astype('float32') arrayencode64 = base64.b64encode(array) arraydecode64 = base64.b64decode(arrayencode64) ARRAY = np.frombuffer(arraydecode64, dtype='float32') print(array) print() print(arrayencode64) print() print(arraydecode64) print() for el in arraydecode64: print(el) print() print(ARRAY)
base64本身只是原始二进制字节流的编码格式,它的编码、解码逻辑完全不感知字节流对应的上层对象结构,只会原样处理二进制内容。
你调用base64.b64encode(array)时,numpy数组会自动输出内部存储的纯数据二进制字节,这个过程会完全丢失numpy数组的所有元信息:包括元素类型dtype、数组形状、维度、步长等属性,编码进base64的只有元素的原始二进制值,没有任何和numpy数组相关的结构信息。
所以base64.b64decode解码后得到的arraydecode64只是普通的bytes类型对象,本质是一串无结构的二进制数据,它自身完全不知道原来对应numpy数组的解析规则,必须通过np.frombuffer显式指定dtype,告诉numpy要把字节流按多少字节切分为一个元素、按什么规则解析数值,才能还原出原始的numpy数组。
如果你希望解码后直接得到完整的numpy数组对象,应该先通过pickle.dumps把整个numpy对象(含所有元信息)序列化为字节流,再做base64编码,解码后再用pickle.loads直接恢复数组对象即可。
arraydecode64是标准的Python bytes类型,遍历该对象时输出的每个数字,就是字节流中单个字节对应的十进制整数值,取值范围固定为0~255。
以你的示例为例:float32类型的每个元素占4个字节,两个元素总共对应8个字节。x86架构默认是小端序,数值1的float32二进制为0x3F800000,拆分为4个字节的顺序为0x00 0x00 0x80 0x3F,对应的十进制就是0、0、128、63;数值2的float32二进制为0x40000000,拆分为4个字节的顺序为0x00 0x00 0x00 0x40,对应的十进制就是0、0、0、64。你遍历打印得到的8个数字就是这8个字节的十进制表示。
内容的提问来源于stack exchange,提问作者Randerson

