不同类型numpy数组tobytes返回格式及C++读取pandas二进制文件问题
核心问题原因
你调用df.to_numpy()得到的数组dtype为object,这类数组在内存中存储的不是实际数值/字符串的内容,而是对应Python对象的内存指针,tobytes输出的内容是这些指针的二进制值,而非你预期的实际数据二进制,所以C++侧直接读取必然得到乱码。
1. numpy的tobytes方法作用
tobytes会直接读取数组在内存中的原始二进制序列并返回,不会做额外的类型转换、结构解析,输出内容完全由数组的dtype定义决定。如果数组是数值类型,输出的就是数值对应的二进制表示;如果是object类型,输出的就是Python对象的内存地址二进制。
2. 混合类型数组tobytes的格式
只要numpy数组的dtype是object,不管里面存的是数值、字符串还是其他Python对象,每个元素占的字节数等于系统指针长度(64位系统占8字节,32位系统占4字节),内容就是该Python对象在当前Python进程中的内存地址,和对象本身的数值没有直接关系,完全无法被其他进程/跨语言直接解析。
正确实现方案
要实现跨语言读取二进制数据,不能使用object类型数组,需要将不同类型的列拆分处理,保证Python侧的dtype和C++侧的类型一一对应:
import pandas as pd import numpy as np df = pd.DataFrame(np.reshape(range(25), (5,5))) df[0] = 101.0 df['ticker'] = 'nick' # 导出数值列,指定为float32对应C++的float类型 numeric_cols = df.iloc[:, :5].to_numpy(dtype=np.float32) # 导出字符串列,转成固定长度4字节的字节类型,对应C++的char[4] str_col = df['ticker'].str.encode('utf-8').to_numpy().astype('S4') # 写入二进制文件 with open('data.bin', 'wb') as f: f.write(numeric_cols.tobytes()) f.write(str_col.tobytes())
对应C++读取代码:
#include <fstream> #include <iostream> using namespace std; int main() { std::fstream f("data.bin", std::ios::binary | std::ios::in); if (!f.is_open()) { printf("open failed"); exit(1); } // 读取5行5列的float数值,共25个float float numeric_buf[25]; f.read((char*)numeric_buf, sizeof(numeric_buf)); cout << numeric_buf[0] << endl; // 输出预期值101 // 读取5个长度为4的字符串 char str_buf[5][4]; f.read((char*)str_buf, sizeof(str_buf)); cout << str_buf[0] << endl; // 输出nick return 0; }
注意事项
- 类型必须严格对应:
np.float32对应C++float、np.float64对应C++double、np.int32对应C++int、固定长度字节类型Sx对应C++char[x] - 同架构下默认字节序一致,跨架构读写需要额外处理大小端转换
- 如果字符串长度不固定,需要先存储每个字符串的长度再存储内容,不要使用
object类型存储可变长度字符串
内容的提问来源于stack exchange,提问作者nick
相关产品推荐
相关产品推荐

