写点什么

Python 存储与读写二进制文件

作者:EquatorCoco
  • 2024-09-10
    福建
  • 本文字数:1502 字

    阅读完需:约 5 分钟

技术背景


一般情况下我们会选择使用明文形式来存储数据,如 json、txt、csv 等等。如果是需要压缩率较高的存储格式,还可以选择使用 hdf5 或者 npz 等格式。还有一种比较紧凑的数据存储格式,就是直接按照二进制格式存储。这种格式下,存储的数据之间没有间隔符,在没有压缩的情况下应该是体积最小的存储类型。


使用方法


在 Python 中,我们可以使用 numpy.tofile()功能,直接将 numpy 数组类型存储到一个二进制文件中。读取的时候,虽然可以直接使用 open(file_name, 'rb')来进行读取,但是为了适配大量 IO 的场景,这里我们使用内存映射 mmap 的形式来进行数据读取。


完整示例


如下是一个完整的示例代码,相关的功能直接用注释的形式在代码中标记:


import numpy as npimport mmapimport resource# 获取页数据量大小(单位:字节)PAGE_SIZE = resource.getpagesize()# 定义单精度浮点数数据占用字节(单位:字节)DATA_SIZE = 4# 计算页存储数据数量(num_float32)PAGE_FNUM = int(PAGE_SIZE/DATA_SIZE)print ("The PAGE_SIZE is: {}".format(PAGE_SIZE))print ("Corresponding float32 numbers should be: {}".format(PAGE_FNUM))# 生成示例数据,使用PAGE_FNUM+4大小的数据量定义两页数据tmp_arr = np.arange(PAGE_FNUM+4).astype(np.float32)# 数据存储路径tmp_file = '/tmp/tmp.dat'# 将数组存储到二进制文件中tmp_arr.tofile(tmp_file)# 每次从二进制文件中读取4个数据READ_NUM = 4with open(tmp_file, 'rb') as file:    # 第一页数据的内存映射    mm = mmap.mmap(file.fileno(), 0, access=mmap.ACCESS_READ, offset=0)    # 第一页数据的1、2、3、4位数据    print (np.frombuffer(mm.read(DATA_SIZE*READ_NUM), dtype='<f4'))    # 第一页数据的5、6、7、8位数据    print (np.frombuffer(mm.read(DATA_SIZE*READ_NUM), dtype='<f4'))    # 第二页数据的内存映射    mm = mmap.mmap(file.fileno(), 0, access=mmap.ACCESS_READ, offset=PAGE_SIZE)    # 第二页数据的1~4位数据    print (np.frombuffer(mm.read(DATA_SIZE*READ_NUM), dtype='<f4'))    # 第二页数据的5~8位数据    print (np.frombuffer(mm.read(DATA_SIZE*READ_NUM), dtype='<f4'))    # 关闭内存映射    mm.close()# 退出文件IO
复制代码


该脚本的输出结果为:


The PAGE_SIZE is: 4096Corresponding float32 numbers should be: 1024[0. 1. 2. 3.][4. 5. 6. 7.][1024. 1025. 1026. 1027.][]
复制代码


结果解析


我们打印的第一个数据是页大小,这里显示是 4096 个字节。而一个单精度浮点数占 4 个字节,所以一页存了 1024 个单精度浮点数,也就是第二个打印输出的结果。由于我们定义的 numpy 数组是一个从 0 开始的递增数组,因此第一页数据的前 8 位数字就是从 0 到 7。而第二页的数据是 1024~1027 一共 4 个浮点数,占 16 个字节。所以我们在第二页第二次使用 numpy.frombuffer()去读取数据的时候,得到的是一个空的数组。此外我们可以查看一下这个二进制文件的大小:


In [1]: import os
In [2]: os.path.getsize('/tmp/tmp.dat')Out[2]: 4112
复制代码


一共是 4112 个字节,刚好是 4096+16 个字节。


总结概要


本文介绍了一种在 Python 中将 Numpy 数组转存为一个紧凑的二进制格式的文件,及其使用内存映射的形式进行读取的方案。一个二进制的数据流,不仅可以更加方便页形式的内存映射,相比于传统的 Numpy 单精度浮点数数组还有一个可哈希的特性。总体来说是一个对于高性能计算十分友好的存储格式,在 cudaSPONGE 中作为一个分子动力学模拟轨迹输出的格式使用。


文章转载自:Dechin 的博客

原文链接:https://www.cnblogs.com/dechinphy/p/18404896/dat

体验地址:http://www.jnpfsoft.com/?from=infoq

用户头像

EquatorCoco

关注

还未添加个人签名 2023-06-19 加入

还未添加个人简介

评论

发布
暂无评论
Python存储与读写二进制文件_Python_EquatorCoco_InfoQ写作社区