python高级编程技巧,如何将文件映射到内存

实际案例
  1. 在访问某些二进制文件时,希望能把文件映射到内存中,可以实现随机访问(如
    framebuffer设备文件);
  2. 某些嵌入式设备,寄存器被编址到内存地址空间,我们可以映射/dev/mem某范围,去访问这些寄存器;
  3. 如果多个进程映射同一个文件,还能实现进程通信的目的。

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

注:本案例在Linux系统下实验。

在shell下,我们通过dd命令创建了一个数据全为0且大小为1M的二进制文件,通过od
-x命令以十六进制的方式查看该文件。

rookie@rookie ~/Desktop $ dd if=/dev/zero of=demo.bin bs=1024 count=10241024+0 records in1024+0 records out1048576 bytes (1.0 MB, 1.0 MiB) copied, 0.007549 s, 139 MB/srookie@rookie ~/Desktop $ od -x demo.bin 0000000 0000 0000 0000 0000 0000 0000 0000 0000*4000000

我们在shell中键入如下命令将二进制文件映射到内存:

>>> f = open('demo.bin', 'r+b')>>> import mmap>>> m = mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_WRITE)>>> type<type 'mmap.mmap'>>>> m[0]'x00'>>> m[10:20]'x00x00x00x00x00x00x00x00x00x00'>>> m[0] = 'x88'rookie@rookie ~/Desktop $ od -x demo.bin 0000000 0088 0000 0000 0000 0000 0000 0000 00000000020 0000 0000 0000 0000 0000 0000 0000 0000*4000000

上述命令中,我们使用Python内置的open()函数来得到文件描述符,并使用f.fileno()来获取文件描述符。除此之外,我们也可使用os模块下的open()函数来得到文件描述符。mmap()函数的第二个参数0表示将整个文件映射到内存,第三个参数mmap.ACCESS_WRITE表示获取写权限。

通过调用mmap()函数,我们可以得到mmap的对象m。我们可以利用这个对象m进行类似列表一样的操作。

注:在mmap()函数中还有一个offset参数,其表示指定映射文件的某个区域,但其必须是内存页大小的整数倍。

>>> m = mmap.mmap(f.fileno(), mmap.PAGESIZE*8, access=mmap.ACCESS_WRITE, offset=mmap.PAGESIZE*4)>>> m[:0x1000] = 'xaa' * 0x1000rookie@rookie ~/Desktop $ od -x demo.bin 0000000 0088 0000 0000 0000 0000 0000 0000 00000000020 0000 0000 0000 0000 0000 0000 0000 0000*0040000 aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa*0050000 0000 0000 0000 0000 0000 0000 0000 0000*4000000

通过上述操作,我们在内存中修改数据的同时也将文件的数据给修改了。因此,我们达到了将文件映射到内存的目的。

注:本部分内容本人也是有点囫囵吞枣,希望路过的大佬能够指点迷津,谢谢!

代码示例:
# _*_ coding:utf-8 _*_
# @Author   : TianYu
# @Time     : 2017/10/16 14:34
# @File     : 如何访问文件的状态.py

import os ,stat
#方法 1 :系统调用:使用标准库中os模块下的三个系统调用stat, fstat, lstat获取文件状态
#stat(path)
#lstat(path):区别是lstat不跟随符号链接
#fstat(fd):传入的参数是一个打开的文件描述符 f.fileno()可以获得
s = os.stat('a1.txt')
bin(s.st_mode) #s.st_mode是一个数,由一些标志位构成,用bin转化为二进制
stat.S_ISDIR(s.st_mode) #判断文件是否是一个文件夹
stat.S_ISREG(s.st_mode) #判断普通文件

print(s.st_mode & stat.S_IRUSR)#判断用户的读权限,只要值大于 0 ,代表为True
print(s.st_mode & stat.S_IXUSR)#判断文件的执行权限

import time
time.localtime(s.st_atime) #文件的最后访问/修改/节点状态更改时间

print(s.st_size) #普通文件的大小

#方法 2:快捷函数:使用标准库中os.path下一些函数,使用起来更加简洁

os.path.isdir('a1.txt')#判断是否是一个目录
os.path.islink('a1.txt')#判断是否是一个符号链接
os.path.isfile('a1.txt') #判断是否是一个普通文件

os.path.getatime('a1.txt') #最后修改时间
os.path.getsize('a1.txt')#普通文件的大小
解决方案:
  1. 使用标准库中mmap模块中的mmap()函数,它需要一个打开的文件描述符作为参数。
代码示例:
# _*_ coding:utf-8 _*_
# @Author   : TianYu
# @Time     : 2017/10/16 15:00
# @File     : 如何使用临时文件.py

#使用临时文件不用命名,且关闭后会自动被删除
#使用标准库中tempfile下的TemporaryFile, NamedTemporaryFile对象

from tempfile import TemporaryFile, NamedTemporaryFile

#TemporaryFile:默认情况下以 w+b(读写,二进制) 的权限打开的
#NamedTemporaryFile:带名字的临时文件

f = TemporaryFile()#一个临时文件的对象,不能由系统的文件系统路径找到,只能由对象f访问
f.write('abcdef' * 100000) #读写临时数据
f.seek(0)#收集完毕后,读会内存中需向将 文件指针指向文件头部
f.read(100) #每次读入临时文件中的一小部分数据

ntf = NamedTemporaryFile()
print(ntf.name()) #描述了ntf在文件系统路径下的字段,每次关闭后会删除

nft = NamedTemporaryFile(delete=False) #参数delete变为False,关闭后,文件系统路径字段不会删除
print(ntf.name())

永利集团304com 1

要努力要奋斗

一. 如何将文件映射到内存?

实际案例:

  1. 在访问某些二进制文件时。希望能把文件映射到内存中,可以实现随机访问。(framebuffer设备文件)
  2. 某些嵌入式设备,寄存器被编址到内存地址空间,我们可以映射/dev/mem某范围,去访问这些寄存器。
  3. 永利集团304com,如果多个进程映射同一个文件,还能实现进程通信的目的。
代码示例:
# _*_ coding:utf-8 _*_
# @Author   : TianYu
# @Time     : 2017/10/16 14:01
# @File     : 如何将文件映射到内存.py

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

#首先:Linux下利用 dd 命令创建一个大小为 1M ,每个字节都是 0 的二进制文件demo.bin
# dd if=/dev/zero of=demo.bin bs=1024 count=1024
#接下来:使用 dd -x demo.bin 命令以十六进制的形式查看文件

#之后进行映射:
import mmap
# mmap.mmap在不同的系统下使用有一些差别
#Windows:mmap(fileno, length[,tagname[,access[,offset]]])
#Unix: mmap(fileno,length[,flags[,prot[,access[,offset]]])
#fileno:文件描述符(不是文件对象),由系统调用的open函数得到的(os模块下的os.open)
#length:映射区域的长度,为 0 的时候映射整个文件
#access:访问权限
#offset:指定文件映射的某一区域

f = open('demo.bin', 'r+b') #权限是 读写 二进制
f.fileno()#报告一个文件描述符
m = mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_WRITE)
print(type(m)) #是mmap.mmap对象,可以有类似数组一样的操作:引索、切片
m[0] = 'x88' #写操作,修改 0 引索下的内容,利用 od -x 命令(Linux下)可以查看文件的变化
m[4:8] = 'xff' * 4 #修改的字符串的长度一定要和切片的长度一致

#注意:mmap函数它必须是“以内存页的大小进行对齐的”offset不能指定跳过文件的 3或5个字节
m = mmap.mmap(f.fileno(), mmap.PAGESIZE * 8, access=mmap.ACCESS_WRITE, offset=mmap.PAGESIZE * 4)
m[:0x1000] = 'xaa' * 0x1000 #之后 od -x 进行查看文件

发表评论

电子邮件地址不会被公开。 必填项已用*标注