14、Python如何将文件映射到内存

首先科普一下,什么叫映射?在计算机程序中,映射(mapping)是一种将一个数据集合中的每个元素(称为“键”)都对应到另一个集合中的唯一元素(称为“值”)的方法。简单理解数组就是映射的一种形式。

那显而易见什么是文件映射,就是将磁盘上的文件的位置,与进程逻辑地址空间中一块大小相同的区域之间的一一对应。映射后得到一个类似数组类型的东西(mmap.mmap()对象),可以通过类似操作数组的方式,达到对文件内容更改的目的。

文件映射到内存的作用:

了解什么是文件映射之后,我们就要思考一下文件映射有什么作用,如下:

1、二进制文件便捷读写

读写二进制文件还在使用open函数?各种组合seek()、read()和write()累不累?尤其二进制文件操作,非常不方便。

二进制文件数据写入文件时是以数组的形式。将数据映射到文件内,然后就以访问数组的形式访问文件,而且在对文件进行修改后,能再次通过此数组将数据同步到文件中。

2、可以提高文件读写效率,避免频繁的进行文件I/O操作

在某些情况下,我们需要处理大文件,例如日志文件、数据库文件等,使用传统的文件读写方式可能会遇到性能问题。为了提高文件处理的效率,我们可以将文件映射到内存中,从而可以直接对内存中的数据进行操作,而不需要频繁地进行磁盘读写操作。

3、某些嵌入式设备,寄存器被编址到内存地址空间,比如/dev/mem,我们可以映射这个文件来访问这些寄存器

如何访问嵌入式设备的寄存器呢?实际上,寄存器就是物理地址的某一特定空间;此时,如果要访问寄存器,只需要将 /dev/mem 的某一范围映射到内存中,用访问内存的方式来访问寄存器;

4、如果多个进程映射同一个文件,还能实现进程通信的目的

多个进程把同一个文件映射到各自的内存空间当中,实际上它们看到的是同一个视图,这样也能实现进程通信的目的。

在python中,如何将文件映射到内存?

使用标准库中mmap模块下的mmap()函数,它需要一个打开的文件描述符作为参数。

# windows版本
mmap.mmap(fileno, length, tagname=None, access=ACCESS_DEFAULT, offset=0)
# Unix 版本
mmap.mmap(fileno, length, flags=MAP_SHARED, prot=PROT_WRITE | PROT_READ, access=ACCESS_DEFAULT, offset=0, *, trackfd=True)
  • fileno:文件描述符;
  • length:映射区域的大小,必须以页(mmap.PAGSIZE)为单位,0表示全部;
  • offset:指定映射文件的某一区域,相当于文件指针,指定的区域必须是页(mmap.PAGESIZE)的整数倍;
  • flags:指明映射的性质。 MAP_PRIVATE 会创建私有的写入时拷贝映射,因此对 mmap 对象内容的修改将为该进程所私有。 而 MAP_SHARED 会创建与其他映射同一文件区域的进程所共享的映射。 默认值为 MAP_SHARED。
  • prot:如果指明了 prot,它将给出所需的内存保护方式;最有用的两个值是 PROT_READ 和 PROT_WRITE,分别指明页面为可读或可写。 prot 默认为 PROT_READ | PROT_WRITE。
  • access:ACCESS_READ , ACCESS_WRITE 或 ACCESS_COPY 分别指定只读,直写或写时复制内存,可以指定 access 作为替代 flags 和 prot 的可选关键字形参。 同时指定 flags, prot 和 access 将导致错误。
  • trackfd:如果 trackfd 为 False,则由 fileno 指定的文件描述符将不会被复制,而结果 mmap 对象将不会被关联到映射的下层文件。 这意味着 size() 和 resize() 方法将会失败。 此模式适用于限制打开文件描述符的数量。
import mmap

# write a simple example file
with open("hello.txt", "wb") as f:
    f.write(b"Hello Python!\n")

with open("hello.txt", "r+b") as f:
    # memory-map the file, size 0 means whole file
    mm = mmap.mmap(f.fileno(), 0)
    # read content via standard file methods
    print(mm.readline())  # prints b"Hello Python!\n"
    # read content via slice notation
    print(mm[:5])  # prints b"Hello"
    # update content using slice notation;
    # note that new content must have same size
    mm[6:] = b" world!\n"
    # ... and read again using standard file methods
    mm.seek(0)
    print(mm.readline())  # prints b"Hello  world!\n"
    # close the map
    mm.close()

mmap内存映射原理

mmap内存映射的实现过程,总的来说可以分为三个阶段:

  1. 进程启动映射过程,并在虚拟地址空间中为映射创建虚拟映射区域;
  2. 调用内核空间的系统调用函数mmap,实现文件物理地址和进程虚拟地址的映射关系
  3. 进程发起对这片映射空间的访问,引发缺页异常,实现文件内容到物理内存(主存)的拷贝

mmap在不同操作系统中的差异

在不同的操作系统中,mmap模块的表现可能会有所不同。这里给一个官方文档的参考:mmap --- 内存映射文件支持 Python 3.13.0rc2 文档

1、文件大小

在 Windows 系统中,通过 mmap 模块创建内存映射文件时,文件大小有限制(通常是 2GB)。而在 Linux 系统中,这个限制要高得多。

2、文件模式

在 Windows 系统中,使用 mmap 时,文件必须以二进制模式打开。在 Linux 系统中,文件可以以文本模式或二进制模式打开。

3、内存映射的保护和访问模式

在 Windows 系统中,mmap 模块的 access 参数不支持 mmap.ACCESS_COPY。而在 Linux 系统中,这个参数是支持的。

4、解除内存映射

在 Windows 系统中,解除内存映射需要调用 m.close() 方法,然后调用 f.close()。在 Linux 系统中,只需调用 m.close() 即可。

5、文件偏移量

在 Windows 系统中,如果文件的大小小于创建内存映射区的大小,那么文件的实际大小将会增加到创建内存映射区的大小。在 Linux 系统中,文件的大小不会因创建内存映射区的大小而改变。​

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

勇敢滴哥哥

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值