Python写入np.float64二进制文件,C++以char读零值为何非零?
问题:Python写入的np.float64二进制文件,C++以char读取时零值显示非零的原因
我用Python生成np.float64类型的数据并写入二进制文件,用C++读取时,以double格式能得到原始数据,但以char格式读取时,原数据中的零值却显示大量非零值。这是什么原因?操作有误吗?
Python写入代码(原版本)
import numpy as np a = np.array([1,3,4,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,4,3,1], dtype=np.float64) with open("temp.txt", "wb") as binary_file: # Write bytes to file for values in a: binary_file.write(values)
C++读取代码(原版本)
#include <fstream> #include <iterator> #include <iostream> #include "compression.h" #include <vector> #include <iomanip> #include <chrono> using namespace std; int main(int argc, char ** argv) { if (argc != 2) { std::cerr << "Need filename" << std::endl; return -1; } // enable check against decompress bool CHECK_ERR = true; std::string file(argv[1]); std::ifstream input(file, std::ios::in | std::ios::binary | std::ios::ate); std::streampos size; size = input.tellg(); input.seekg(0, std::ios::beg); // Reading data as double std::vector<double> fileData(size/sizeof(double)); input.read((char*) &fileData[0], size); // This will generate the correct values, which I need for (int i=0; i<fileData.size(); i++ ) cout<< fileData.at(i)<<" "; cout << endl; // Reading data in character format std::ifstream inputChr(file, std::ios::in | std::ios::binary | std::ios::ate); inputChr.seekg(0, std::ios::beg); while(size >= 64) { char memblock[64]; inputChr.read((char*) &memblock, 64); cout << "Character values "<< endl; for (int i=0; i<64; i++) cout << +(memblock[i]) << " "; cout << endl; size--; } return 0; }
原因分析与解决方案
1. Python写入代码的核心错误
binary_file.write(values)的写法是无效的,file.write()要求传入字节对象,而直接传入np.float64标量会触发类型错误。错误的写入方式会导致文件内容并非正确的double二进制表示,这是读取异常的根源之一。
正确的写入方式应该将numpy标量转换为字节流,或者直接写入整个数组:
import numpy as np a = np.array([1,3,4,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,4,3,1], dtype=np.float64) with open("temp.bin", "wb") as binary_file: # 高效写法:一次性写入整个数组的字节流 a.tofile(binary_file) # 或循环写入每个元素: # for val in a: # binary_file.write(val.tobytes())
2. C++读取代码的循环逻辑错误
原代码中size--的逻辑完全错误:每次读取64字节后,剩余字节数应该减去64,而非1。当前逻辑会导致循环执行数百次,反复读取文件内容,甚至读取文件末尾外的操作系统垃圾数据,这些垃圾值就是你看到的“非零值”。
修正后的C++读取逻辑:
#include <fstream> #include <iterator> #include <iostream> #include "compression.h" #include <vector> #include <iomanip> #include <chrono> using namespace std; int main(int argc, char ** argv) { if (argc != 2) { std::cerr << "Need filename" << std::endl; return -1; } bool CHECK_ERR = true; std::string file(argv[1]); std::ifstream input(file, std::ios::in | std::ios::binary | std::ios::ate); std::streampos totalSize = input.tellg(); input.seekg(0, std::ios::beg); // 以double读取(原逻辑正确,保留) std::vector<double> fileData(totalSize/sizeof(double)); input.read(reinterpret_cast<char*>(&fileData[0]), totalSize); for (double val : fileData) cout << val << " "; cout << endl; // 以char读取,修正循环逻辑 std::ifstream inputChr(file, std::ios::in | std::ios::binary); std::streampos remainingSize = totalSize; inputChr.seekg(0, std::ios::beg); while(remainingSize >= 64) { char memblock[64]; inputChr.read(memblock, 64); cout << "Character values:" << endl; for (int i=0; i<64; i++) cout << +static_cast<signed char>(memblock[i]) << " "; cout << endl; remainingSize -= 64; } // 处理剩余不足64字节的部分 if (remainingSize > 0) { char memblock[64]; inputChr.read(memblock, remainingSize); cout << "Remaining character values:" << endl; for (int i=0; i<remainingSize; i++) cout << +static_cast<signed char>(memblock[i]) << " "; cout << endl; } return 0; }
3. 浮点数二进制存储的补充说明
np.float64对应C++的double类型,占8字节。IEEE 754标准中,数值0.0的double二进制表示是全8字节0,修正代码后,以char读取零值时会显示连续8个0,符合预期。
内容的提问来源于stack exchange,提问作者nivedita
相关产品推荐
相关产品推荐

