Python高效存储与读取二进制文件的完整方案

白榆
白榆
发布时间:2026-10-11| 3人浏览过
原创

针对需要极致体积与快速IO的场景,本文详细介绍如何利用Python的NumPy将数组导出为紧凑的二进制流,并结合内存映射(mmap)实现零拷贝读取。通过页对齐策略验证文件大小与数据对应关系,提供可直接运行的完整代码,适用于高性能计算与大数据文件读写。

二进制存储优势与适用场景

常规文本格式(如JSON、TXT、CSV)在存储结构化数据时便于人类阅读,但存在大量分隔符与编码开销。追求压缩率时可采用HDF5或NPZ等容器格式。而在对传输带宽敏感或需直接对接底层C/C++接口的场景中,直接使用纯二进制流存储是体积最小且解析最快的选择。该格式下数据连续排列无间隔,配合内存映射可实现接近内存速度的一站式读写。

环境准备与参数说明

本方案依赖Python标准库与第三方科学计算包。核心参数由运行环境自动获取,无需手动硬编码,确保跨平台兼容性。

  • resource.getpagesize():获取当前操作系统的内存页大小(通常为4096字节),用于划分映射区间。
  • np.float32:单精度浮点数,固定占用4字节,保证数据类型与C语言标准一致。
  • mmap.ACCESS_READ:声明只读访问模式,避免意外修改底层数据。

第1步:初始化配置并生成基准数据

目的:建立页大小与数据数量的对应关系,构造覆盖两个完整内存页的测试数组。
入口/动作:导入numpy、mmap与resource,计算单页可承载的float32数量。使用np.arange()生成从0开始的递增数组。
参数:PAGE_SIZE(系统页宽)、DATA_SIZE=4(类型字节数)、tmp_file='/tmp/tmp.dat'(临时存储路径)。
完成状态:终端打印出预期页容量(如1024),内存中生成指定长度的浮点型数组。

import numpy as np
import mmap
import resource

# 获取系统内存页大小(单位:字节)
PAGE_SIZE = resource.getpagesize()
# 定义单精度浮点数占用空间
DATA_SIZE = 4
# 计算一页可容纳的数值数量
PAGE_FNUM = int(PAGE_SIZE / DATA_SIZE)

print(f"The PAGE_SIZE is: {PAGE_SIZE}")
print(f"Corresponding float32 numbers should be: {PAGE_FNUM}")

# 生成示例数据(总量覆盖两页,并多出4个元素)
tmp_arr = np.arange(PAGE_FNUM + 4).astype(np.float32)
tmp_file = "/tmp/tmp.dat"

第2步:将NumPy数组写入二进制文件

目的:消除文本分隔符,将连续的内存块直接转储为磁盘文件。
入口/动作:调用NumPy数组内置方法.tofile()。
参数:tmp_file(输出路径)。该方法会按字节序逐帧写入,不添加任何头文件或元数据。
完成状态:磁盘生成同名二进制文件,无后缀扩展名限制,内容为纯十六进制流。

# 直接序列化到磁盘
# 注意:生产环境建议先用shutil.copyfileobj备份原文件防止覆盖风险
tmp_arr.tofile(tmp_file)

第3步:利用mmap按需读取内存映射

目的:避免read()带来的频繁内核态切换,直接通过虚拟内存地址解析文件片段。
入口/动作:以'rb'模式打开文件句柄,实例化mmap.mmap对象。通过调整offset参数定位特定页,使用np.frombuffer()将映射区域转为数组。
参数:access=mmap.ACCESS_READ、offset(起始字节位置)、dtype='<f4'(Little-Endian Float32)。
完成状态:成功打印对应索引区间的数值列表,处理完毕后调用.close()释放映射表项。

READ_NUM = 4  # 单次读取的数据点数
with open(tmp_file, 'rb') as file:
    # 映射第一页内存(基址偏移0)
    mm = mmap.mmap(file.fileno(), 0, access=mmap.ACCESS_READ, offset=0)
    print(np.frombuffer(mm.read(DATA_SIZE * READ_NUM), dtype="<f4"))
    print(np.frombuffer(mm.read(DATA_SIZE * READ_NUM), dtype="<f4"))

    # 映射第二页内存(按页边界偏移)
    mm = mmap.mmap(file.fileno(), 0, access=mmap.ACCESS_READ, offset=PAGE_SIZE)
    print(np.frombuffer(mm.read(DATA_SIZE * READ_NUM), dtype="<f4"))
    # 超出文件实际剩余长度,安全返回空列表
    print(np.frombuffer(mm.read(DATA_SIZE * READ_NUM), dtype="<f4"))
    mm.close()

结果核对与运行状态判断

执行上述脚本后,终端输出应呈现以下特征:

  1. 页容量确认:The PAGE_SIZE is: 4096与1024表明系统分配4KB物理页,可精准装入1024个float32。
  2. 第一页数据:前两行分别输出[0. 1. 2. 3.]与[4. 5. 6. 7.],证明从基址开始顺序切片成功。
  3. 第二页数据:第三行输出[1024. 1025. 1026. 1027.],符合数组索引跨越页边界的逻辑。第四行为空列表[],因剩余有效字节不足16B(4个点),触发安全截断。
  4. 磁盘体积验证:可通过os.path.getsize(tmp_file)核对结果为4112,恰好等于4096 + 16,与理论计算完全一致。

方案总结

通过.tofile()结合mmap读取的方案,彻底规避了传统文件I/O的缓冲复制开销。二进制流不仅体积最小,其连续内存布局天然适配GPU直读与哈希索引,已成为分子动力学轨迹、高频交易Tick数据等高吞吐场景的标准选型。对于后续接入深度学习训练管道的项目,建议在入库前增加校验和(Checksum)机制以防静默损坏。以上就是Python存储与读写二进制文件的详细内容,更多关于Python二进制数据处理的资料请关注本站其它相关文章!

相关标签:

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。