要求:
在访问某些二进制文件时,希望能把文件映射到内存中,可以像数组一样实现随机访问(例如linux的framebuffer设备文件)。
某些嵌入式设备,寄存器被编址到内存地址空间,可以映射linux的
/dev/mem
某范围,去访问这些寄存器。如果多个进程同时映射同一个文件,还能实现进程通信的目的。
解决方案:
使用标准库中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()
函数也会直接返回一个文件描述符对象。
- 方案示例:
- 拷贝一个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
- 将
demo.bin
映射到内存中
>>> f = open('demo.bin', 'r+b')>>> f.fileno()3>>> m = mmap.mmap(f.fileno(), 0)>>> m<mmap.mmap object at 0x7f74cf940978>
- 向内存写入数据
>>> 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
- 像数组一样访问、写入
>>> 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桌面测试。