mmap python Python的mmap,让文件读写快得像坐火箭,你还在傻傻用传统I/O?

1. mmap内存映射文件

创建一个文件的内存映射, 会运用操作系统虚拟内存去直接访问文件系统里的数据, 并非运用常规的I/O函数获取数据。内存映射一般能够给予I/O性能, 鉴于使用内存映射时, 用不着为每个访问构建一个独立的系统调用, 也无需在缓冲区之间拷贝数据;事实上, 内核以及用户应用均可直接访问内存。

内存映射文件, 可被视作可修改的字符串, 或者类似文件的对象, 这要依据具体的需求来定。映射文件, 对一般的文件API方法予以支持, 像close()、flush()、read()、()、seek()、tell()以及write()。它同样支持字符串API, 能提供类似分片这样的特性, 还有类似find()的方法。

下述所有示例, 均会选用文本文件lorem.txt, 该文件之中存有一些Lorem Ipsum。为方便参考起见, 以下代码清单呈现出此文件的文本内容。

坐在那里的人身上有洛伦 ipsum 这个东西, 是痛苦的, 精英人士。

Donec , enim et , leo,

. Sed eros eu . vel

弯弯的, 纯净的兽穴, 并且, 处于, 在……之中, 和……同时。

湖泊, 然而却是草皮。现在, 那片区域, 直径。

dui. morbi et netus et

fames ac .

Leo, 没有增大的那个没有, 然而, 有沉淀。

in nibh . .

massa. Ut eget velit .

justo.

1.1 读文件

运用mmap()函数能够创建出一个内存映射文件, 第一个参数乃是文件描述符, 其有可能源自file对象的()方法, 又或许源自os.open(), 而调用者在调用mmap()之前需承担起打开文件的职责, 在不再需要该文件之时要履行将其关闭的责任。

mmap()的第二个参数所指示的, 是那要进行映射的文件部分的大小, 此大小用字节作为单位来衡量。要是这个值为0, 那么便会映射整个文件。倘若所指示的这个大小, 比文件的当前大小还要大, 那就会对该文件进行扩展。

这两个平台均支持一个可选择的关键字参数, 使用它意味着只读访问, 它还表示“写通过”, 也就是对内存的赋值会直接写入文件, 它又表示“写时复制”,此时对内存的赋值不会写至文件。


import mmap
with open('lorem.txt', 'r') as f:
  with mmap.mmap(f.fileno(), 0,
          access=mmap.ACCESS_READ) as m:
    print('First 10 bytes via read :', m.read(10))
    print('First 10 bytes via slice:', m[:10])
    print('2nd  10 bytes via read :', m.read(10))

通过一个分片操作访问的最后一个字节, 会由文件指针进行跟踪, 在这个例子当中, 第一次进行读操作之后, 指针随之向前移动10个字节, 随后, 分片操作会把指针重新设定回到文件的起始位置, 并让指针经过分片操作, 再次向前前行10个字节之后, 再去调用read(), 便会给出文件的11至20字节。

1.2 写文件

存在这样一种情况, 即需要去构建内存映射文件, 以此来接纳更新, 在进行映射之前, 首先得运用模式'r+'(而非'w')来打开文件, 目的是最终完成追加, 随后能够采用任何一种会对数据产生改变的API方法(像是write()或者赋值到一个分片等诸如此类的方法)。

底下的示例运用了默认访问样式, 且赋予了一个分片, 从而在原地对某一行的一部分实施修改。


import mmap
import shutil
# Copy the example file
shutil.copyfile('lorem.txt', 'lorem_copy.txt')
word = b'consectetuer'
reversed = word[::-1]
print('Looking for  :', word)
print('Replacing with :', reversed)
with open('lorem_copy.txt', 'r+') as f:
  with mmap.mmap(f.fileno(), 0) as m:
    print('Before:\n{}'.format(m.readline().rstrip()))
    m.seek(0) # rewind
    loc = m.find(word)
    m[loc:loc + len(word)] = reversed
    m.flush()
    m.seek(0) # rewind
    print('After :\n{}'.format(m.readline().rstrip()))
    f.seek(0) # rewind
    print('File :\n{}'.format(f.readline().rstrip()))

内存的文件中第一行中间的单词“”将被替换。

mmap python_mmap内存映射文件_内存映射文件API

使用访问设置时不会把修改写入磁盘上的文件。


import mmap
import shutil
# Copy the example file
shutil.copyfile('lorem.txt', 'lorem_copy.txt')
word = b'consectetuer'
reversed = word[::-1]
with open('lorem_copy.txt', 'r+') as f:
  with mmap.mmap(f.fileno(), 0,
          access=mmap.ACCESS_COPY) as m:
    print('Memory Before:\n{}'.format(
      m.readline().rstrip()))
    print('File Before :\n{}\n'.format(
      f.readline().rstrip()))
    m.seek(0) # rewind
    loc = m.find(word)
    m[loc:loc + len(word)] = reversed
    m.seek(0) # rewind
    print('Memory After :\n{}'.format(
      m.readline().rstrip()))
    f.seek(0)
    print('File After  :\n{}'.format(
      f.readline().rstrip()))

于这个例子里, 得要单独地回转文件句柄, 此外还得单独地回转mmap句柄, 缘由在于这两个对象的内部状态是会单独予以维护的。

内存映射文件API_mmap内存映射文件_mmap python

1.3 正则表达式

鉴于内存映射文件跟一个字符串相类似, 所以它也常常会同其他处理字符串的模块一块儿被使用, 像正则表达式。下面的这个例子会将所有含有“nulla”的句子给找出来。


import mmap
import re
pattern = re.compile(rb'(\.\W+)?([^.]?nulla[^.]*?\.)',
           re.DOTALL | re.IGNORECASE | re.MULTILINE)
with open('lorem.txt', 'r') as f:
  with mmap.mmap(f.fileno(), 0,
          access=mmap.ACCESS_READ) as m:
    for match in pattern.findall(m):
      print(match[1].replace(b'\n', b' '))

因为鉴于这个模式涵盖着两个组, 因而()的返回值是一系列的元组。print语句将寻觅到相匹配的句子, 并且用以空格替换换行符之方式, 致使各个结果均打印于同一行之上。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值