22. 将文件映射到内存

要求:

  1. 在访问某些二进制文件时,希望能把文件映射到内存中,可以像数组一样实现随机访问(例如linux的framebuffer设备文件)。

  2. 某些嵌入式设备,寄存器被编址到内存地址空间,可以映射linux的/dev/mem某范围,去访问这些寄存器。

  3. 如果多个进程同时映射同一个文件,还能实现进程通信的目的。

解决方案:

使用标准库中mmap.mmap()函数,将文件映射到进程的内存地址空间。


  • 对于mmap.mmap()函数:
mmap.mmap(fileno, length, tagname, access, offset)

从文件描述符fileno指定的文件映射长度字节,并返回一个mmap对象。如果length为0,则映射的最大长度将是调用mmap时文件的当前大小。

>>> import mmap>>> mmap.PAGESIZE4096

offset为起始映射的偏移量,是页对齐的,必须以mmap.PAGESIZE为单位。

  • 对于文件描述符:

内核利用文件描述符来访问文件。文件描述符是非负整数。打开现存文件或新建文件时,内核会返回一个文件描述符。读写文件也需要使用文件描述符来指定待读写的文件。

>>> f = open('demo.bin', 'r+b')>>> f.fileno()3

如果使用os.open()函数也会直接返回一个文件描述符对象。


  • 方案示例:
  1. 拷贝一个1MB的全0的特殊文件为demo.bin
# dd if=/dev/zero of=demo.bin bs=1024 count=1024                #拷贝 /dev/zero 文件为 demo.bin 文件,大小为1M1024+0 records in1024+0 records out
1048576 bytes (1.0 MB) copied, 0.00273495 s, 383 MB/s# od -x demo.bin                #以16进制查看二进制文件0000000 0000 0000 0000 0000 0000 0000 0000 0000
*
4000000

  1. demo.bin映射到内存中
>>> f = open('demo.bin', 'r+b')>>> f.fileno()3>>> m = mmap.mmap(f.fileno(), 0)>>> m<mmap.mmap object at 0x7f74cf940978>

  1. 向内存写入数据
>>> m.write(b'abc')3

# od -x demo.bin0000000 6261 0063 0000 0000 0000 0000 0000 0000             #61、62、63分别是a、b、c十六进制的ASCII码0000020 0000 0000 0000 0000 0000 0000 0000 0000
*
4000000

  1. 像数组一样访问、写入
>>> m[0]97>>> m[5]0>>> m[5] = 78

# od -x demo.bin0000000 6261 0063 4e00 0000 0000 0000 0000 0000             #4e即是78的十六进制数0000020 0000 0000 0000 0000 0000 0000 0000 0000
*
4000000

>>> m[8:16]b'\x00\x00\x00\x00\x00\x00\x00\x00'>>> m[8:16] = b'\xff' * 8               #像切片一样写入

# od -x demo.bin0000000 6261 0063 4e00 0000 ffff ffff ffff ffff             #已经修改为ff0000020 0000 0000 0000 0000 0000 0000 0000 0000
*
4000000


  • 方案示例:
# ll /dev/fb0 crw-rw---- 1 root video 29, 0 Aug 28 21:03 /dev/fb0

import mmap

f = open('/dev/fb0', 'r+b')              #linux的/dev/fb0文件即framebuffer设备文件size = 1920 * 1080 * 4m = mmap.mmap(f.fileno(), size)             #映射到内存中m[:size//2] = b'\xff\xff\xff\x00' * (size // 4 // 2)                #修改内存一半的值m.close()f.close()

在终端模式下以root身份运行后使linux终端屏幕黑白上下各占一半。

由于我没有安装linux桌面,效果似乎不太一样,似乎全屏变白,最好是使用linux桌面测试。

22. 将文件映射到内存


上一篇:mmap是否与所有进程共享内存?


下一篇:linux – 映射文件的非线性部分