首页 > Python基础教程 >
-
Python3标准库:mmap内存映射文件
1. mmap内存映射文件
建立一个文件的内存映射将使用操作系统虚拟内存来直接访问文件系统上的数据,而不是使用常规的I/O函数访问数据。内存映射通常可以提供I/O性能,因为使用内存映射是,不需要对每个访问都建立一个单独的系统调用,也不需要在缓冲区之间复制数据;实际上,内核和用户应用都能直接访问内存。
内存映射文件可以看作是可修改的字符串或类似文件的对象,这取决于具体的需要。映射文件支持一般的文件API方法,如close()、flush()、read()、readline()、seek()、tell()和write()。它还支持字符串API,提供分片等特性以及类似find()的方法。
下面的所有示例都会使用文本文件lorem.txt,其中包含一些Lorem Ipsum。为便于参考,下面的代码清单给出这个文件的文本。
- Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
- Donec egestas, enim et consectetuer ullamcorper, lectus ligula rutrum leo,
- a elementum elit tortor eu quam. Duis tincidunt nisi ut ante. Nulla
- facilisi. Sed tristique eros eu libero. Pellentesque vel
- arcu. Vivamus purus orci, iaculis ac, suscipit sit amet, pulvinar eu,
- lacus. Praesent placerat tortor sed nisl. Nunc blandit diam egestas
- dui. Pellentesque habitant morbi tristique senectus et netus et
- malesuada fames ac turpis egestas. Aliquam viverra fringilla
- leo. Nulla feugiat augue eleifend nulla. Vivamus mauris. Vivamus sed
- mauris in nibh placerat egestas. Suspendisse potenti. Mauris
- massa. Ut eget velit auctor tortor blandit sollicitudin. Suspendisse
- imperdiet justo.
1.1 读文件
使用mmap()函数可以创建一个内存映射文件。第一个参数是文件描述符,可能来自file对象的fileno()方法,也可能来自os.open()。调用者在调用mmap()之前负责打开文件,不再需要文件时要负责将其关闭。
mmap()的第二个参数是要映射的文件部分的大小(以字节为单位)。如果这个值为0,则映射整个文件。如果这个大小大于文件的当前大小,则会扩展该文件。
这两个平台都支持一个可选的关键字参数access。使用ACCESS_READ表示只读访问;ACCESS_WRITE表示“写通过”(write-through),即对内存的赋值直接写入文件;ACCESS_COPY表示“写时复制”(copy-on-write),对内存的赋值不会写至文件。
- 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()或赋值到一个分片等)。
下面的例子使用了默认访问模式ACCESS_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()))
内存的文件中第一行中间的单词“consectetuer”将被替换。
使用访问设置ACCESS_COPY时不会把修改写入磁盘上的文件。
- 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(