Python存储与读写二进制文件

news/2024/10/3 2:21:05

技术背景

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

使用方法

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

完整示例

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

import numpy as np
import mmap
import 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 = 4
with 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: 4096
Corresponding 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 osIn [2]: os.path.getsize('/tmp/tmp.dat')
Out[2]: 4112

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

总结概要

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

版权声明

本文首发链接为:https://www.cnblogs.com/dechinphy/p/dat.html

作者ID:DechinPhy

更多原著文章:https://www.cnblogs.com/dechinphy/

请博主喝咖啡:https://www.cnblogs.com/dechinphy/gallery/image/379634.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.ryyt.cn/news/58398.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈,一经查实,立即删除!

相关文章

IIS标识介绍

原文链接:https://blog.csdn.net/weixin_30607659/article/details/95294969 应用程序池的标识是运行应用程序池的工作进程所使用的服务帐户名称。默认情况下,应用程序池以 Network Service 用户帐户运行,该帐户拥有低级别的用户权限。您可以将应用程序池配置为以 Windows S…

SQL SERVER -- JSON处理

-- JSON 字符串转 行记录 Declare @JsonStr Nvarchar(Max)=[{"State":0,"Name":"语文","ReMark":"了解国学信息","RepDtl":[{"ID":1,"Age":11},{"ID":2,"Age":12},{&quo…

添加字体(以课堂“谁能许我扶桑花期字体“为例)

1.进入https://font.chinaz.com/此网址,在搜索栏搜索“谁能许我扶桑花期字体”,点击下载 2.下载后为font1618.rar压缩文件,将文件放于桌面并进行解压 3.解压后的文件夹中包括三个文件,如图将【谁能许我扶桑花期】.ttf文件进行复制 4.打开“我的电脑(计算机)”,在地址栏输入…

2-4Java重写与重载

Java 重写与重载 重写(Override) 重写是子类对父类的允许访问的方法的实现过程进行重新编写, 返回值和形参都不能改变。即外壳不变,核心重写! 重写的好处在于子类可以根据需要,定义特定于自己的行为。 也就是说子类能够根据需要实现父类的方法。 重写方法不能抛出新的检查异…

django 路由相关

路由系统 1 常见操作 通俗的语言来表示:URL -> 函数对应关系2 路由源码分析 2.1 路由定义的本质from django.urls import path, re_path from apps.www import viewsfrom django.urls import URLPattern from django.urls.resolvers import RoutePatternurlpatterns = […

django环境相关

1.项目相关新项目开发时,可能遇到使用其他的版本。 虚拟环境老项目打开项目 虚拟环境1.1 关于新项目 1.系统解释器+命令行【学习】 C:/python38- python.exe- Scripts- pip.exe- pip3.8.exe- django-admin.exe- Lib- re.py- site-pakages- djangoC:/python39- python.exe- Scr…

高等数学 1.2数列的极限

目录数列极限的定义数列的概念数列极限的定义收敛数列的性质 数列极限的定义 数列的概念 如果按照某一法则,对每个 \(n \in \mathbb{N}_+\) ,对应着一个确定的实数 \(x_n\) ,这些实数 \(x_n\) 按照下标 \(n\) 从大到小排列得到的一个序列 \[x_1, x_2, x_3, \cdots, x_n, \cd…

gti前端代码提交

git bash中前端切换分支提交遇到的不懂的地方第一次gti前端提交 根据提示一步步看 首先 git check dev此时可能会报错: error: Your local changes to the following files would be overwritten by checkout: .env.development package.json Please commit your changes or s…