问题23:如何将文件映射到内存
一、说明
1)什么叫映射?
==>就是给一个对象(可以是变量、物理等),起一个唯一的别名,建立一一对应的关系;
2)文件映射:将磁盘上的文件的位置,与进程逻辑地址空间中一块大小相同的区域之间的一一对应;
3)映射后得到一个类似数组类型的东西(mmap.mmap()对象),可以通过类似操作数组的方式,达到对文件内容更改的目的;
二、优点
1)相对于二进制文件的缺陷
通常读写文件时,使用read()和write()方法,这两种方法都是以流的形式进行的,也就是一个字节接着一个字节的读写;如果想从某一位置开始读写,使用seek()方法调整文件指针,此方法对二进制文件的操作非常不方便,因为相对于二进制文件,数据写入文件时是以数组的形式,将数据映射到文件内,然后就以访问数组的形式访问文件,而且在对文件进行修改后,能再次通过此数组将数据同步到文件中;
2)某些嵌入式设备,寄存器被编址到内存地址空间,我们可以映射/dev/mem某范围,取访问这些寄存器
例如:在树莓派(为学习计算机编程教育设计的一种微型电脑)上,有一个pwm波形的发生器,若想使用此发生器,就要访问树莓派的寄存器;实际上,寄存器就是物理地址的某一特定空间;此时,如果要访问寄存器,需要将 /dev/mem 的某一范围,映射到内存中,用访问内存的方式来访问寄存器;
3)如果多个进程映射同一个文件,还能实现进程通信的目的
多个进程把同一个文件映射到各自的内存空间当中,实际上它们看到的是同一个视图,也能实现进程通信的目的;
三、python中,如何做到文件映射到内存?
1)方案:使用标准库中mmap模块下的mmap()函数,它需要一个打开的文件描述符作为参数
2)格式:mmap.mmap(fileno, length[, access[, offset]]])
#fileno:文件描述符;
f = open('a.txt', 'w')
f.fileno(),得到文件a.txt的描述符;
#length:映射区域的大小,必须以页(mmap.PAGSIZE)为单位;
#页(mmap.PAGSIZE):磁盘的存储单位;
A、0,表示全部文件;
B、length = mmap.PAGSIZE * 8:只映射文件的前8页;
#access:访问权限;如access = mmap.ACCESS_WRITE,表示写的权限;
#offset:指定映射文件的某一区域,相当于文件指针;
A、指定时必须要以内存的一个页做为单位,进行文件和内存的对齐,也就是说,不能随意跳过一些字节来指定映射区域;
B、指定的区域必须是页(mmap.PAGESIZE)的整数倍;
C、offset = mmap.PAGSIZE * 4:表示跳过4页,从第5页开始映射;
3)例:
import mmap f = open('demo.bin', 'rb') m = mmap.mmap(f.fileno(), mmap.PAGSIZE * 8, access = mmap.ACCESS_WRITE, offset = mmap.PAGSET * 4) #f.fileno():得到demo.bin文件的文件描述符; #mmap.PAGSIZE * 8:映射8页; #access = mmap.ACCESS_WRITE:以写权限对被映射的文件内容进行操作; #offset = mmap.PAGSIZE * 4:从第5页开始对文件进行映射; #此处的页,页就是mmap.PAGSIZE是指内存的存储单元; #此时文件在磁盘上,并没有被Copy到内存上; print(type(m)) #输出:mmap.mmap() #对单个位置的字节进行更改; m[0] = 'x88' #切片:对一段数据进行更改;长度要和赋值的二进制字符串程度一样; m[4:8] = 'x01'*4
4)其它
A、不同的平台(也就是系统)上,mmap()函数的使用不同;
B、文件描述符:是系统调用的open函数,在打开文件时得到的;(os.open())
C、python中的open()函数也可以得到文件描述符: