16.7. mmap — 内存映射文件支持 — Python 文档

来自菜鸟教程
Python/docs/2.7/library/mmap
跳转至:导航、​搜索

16.7. 映射 — 内存映射文件支持

内存映射文件对象的行为既像字符串又像文件对象。 然而,与普通的字符串对象不同,这些对象是可变的。 您可以在大多数需要字符串的地方使用 mmap 对象; 例如,您可以使用 re 模块搜索内存映射文件。 由于它们是可变的,您可以通过执行 obj[index] = 'a' 更改单个字符,或通过分配给切片来更改子字符串:obj[i1:i2] = '...'。 也可以从当前文件位置开始读写数据,通过文件seek()到不同位置。

内存映射文件由 mmap 构造函数创建,这在 Unix 和 Windows 上是不同的。 无论哪种情况,您都必须为打开以进行更新的文件提供文件描述符。 如果您希望映射现有 Python 文件对象,请使用其 fileno() 方法获取 fileno 参数的正确值。 否则,您可以使用 os.open() 函数打开文件,该函数直接返回文件描述符(完成后仍需要关闭文件)。

笔记

如果要为可写的缓冲文件创建内存映射,则应首先 flush() 该文件。 这是必要的,以确保对缓冲区的本地修改实际上可用于映射。


对于 Unix 和 Windows 版本的构造函数,可以将 access 指定为可选关键字参数。 access 接受以下三个值之一:ACCESS_READ、ACCESS_WRITE 或 ACCESS_COPY 指定只读、直写或写时复制内存分别。 access 可以在 Unix 和 Windows 上使用。 如果未指定 access,则 Windows mmap 返回直写映射。 所有三种访问类型的初始内存值均取自指定文件。 分配给 ACCESS_READ 内存映射会引发 TypeError 异常。 分配给 ACCESS_WRITE 内存映射会影响内存和底层文件。 分配给 ACCESS_COPY 内存映射会影响内存但不会更新底层文件。

2.5 版更改: 要映射匿名内存,-1 应作为文件号与长度一起传递。


2.6 版更改: mmap.mmap 以前是创建 mmap 对象的工厂函数。 现在 mmap.mmap 是类本身。


class mmap.mmap(fileno, length[, tagname[, access[, offset]]])

(Windows 版本) 从文件句柄 fileno 指定的文件映射 length 个字节,并创建一个 mmap 对象。 如果 length 大于文件的当前大小,则文件被扩展为包含 length 个字节。 如果 length 为 0,则映射的最大长度为文件的当前大小,除非文件为空 Windows 引发异常(您不能在 Windows 上创建空映射) )。

tagname,如果指定而不是 None,是一个字符串,给出映射的标记名称。 Windows 允许您对同一个文件进行许多不同的映射。 如果您指定现有标签的名称,则会打开该标签,否则会创建具有该名称的新标签。 如果省略此参数或 None,则创建的映射没有名称。 避免使用 tag 参数将有助于保持您的代码在 Unix 和 Windows 之间的可移植性。

offset 可以指定为非负整数偏移量。 mmap 引用将相对于文件开头的偏移量。 offset 默认为 0。 offset 必须是 ALLOCATIONGRANULARITY 的倍数。

class mmap.mmap(fileno, length[, flags[, prot[, access[, offset]]]])

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

flags 指定映射的性质。 MAP_PRIVATE 创建一个私有的写时复制映射,因此对 mmap 对象内容的更改将是该进程私有的,并且 MAP_SHARED 创建一个与所有其他进程共享的映射文件的相同区域。 默认值为 MAP_SHARED。

prot,如果指定,则提供所需的内存保护; 两个最有用的值是 PROT_READ 和 PROT_WRITE,用于指定可以读取或写入的页面。 prot 默认为 PROT_READ | PROT_WRITE。

可以指定 access 代替 flags 和 prot 作为可选关键字参数。 同时指定 flags、prot 和 access 是错误的。 有关如何使用此参数的信息,请参见上文 access 的说明。

offset 可以指定为非负整数偏移量。 mmap 引用将相对于文件开头的偏移量。 offset 默认为 0。 offset 必须是 ALLOCATIONGRANULARITY 的倍数,在 Unix 系统上等于 PAGESIZE。

为了确保创建的内存映射的有效性,由描述符 fileno 指定的文件在内部自动与 Mac OS X 和 OpenVMS 上的物理后备存储同步。

这个例子展示了一个使用 mmap 的简单方法:

import mmap

# write a simple example file
with open("hello.txt", "wb") as f:
    f.write("Hello Python!\n")

with open("hello.txt", "r+b") as f:
    # memory-map the file, size 0 means whole file
    mm = mmap.mmap(f.fileno(), 0)
    # read content via standard file methods
    print mm.readline()  # prints "Hello Python!"
    # read content via slice notation
    print mm[:5]  # prints "Hello"
    # update content using slice notation;
    # note that new content must have same size
    mm[6:] = " world!\n"
    # ... and read again using standard file methods
    mm.seek(0)
    print mm.readline()  # prints "Hello  world!"
    # close the map
    mm.close()

下一个示例演示如何创建匿名映射并在父进程和子进程之间交换数据:

import mmap
import os

mm = mmap.mmap(-1, 13)
mm.write("Hello world!")

pid = os.fork()

if pid == 0:  # In a child process
    mm.seek(0)
    print mm.readline()

    mm.close()

内存映射文件对象支持以下方法:

close()

关闭 mmap。 对该对象的其他方法的后续调用将导致引发 ValueError 异常。 这不会关闭打开的文件。

find(string[, start[, end]])

返回对象中找到子字符串 string 的最低索引,使得 string 包含在 [start, end 范围内]。 可选参数 start 和 end 被解释为切片符号。 失败时返回 -1。

flush([offset, size])

将对文件的内存副本所做的更改刷新回磁盘。 如果不使用此调用,则无法保证在销毁对象之前写回更改。 如果指定了 offset 和 size,则只有对给定字节范围的更改才会刷新到磁盘; 否则,整个映射范围将被刷新。 offset 必须是 PAGESIZE 或 ALLOCATIONGRANULARITY 的倍数。

(Windows 版) 返回非零值表示成功; 零表示失败。

(Unix 版本) 返回零值表示成功。 调用失败时会引发异常。

move(dest, src, count)

将从偏移量 src 开始的 count 字节复制到目标索引 dest。 如果 mmap 是使用 ACCESS_READ 创建的,则调用 move 将引发 TypeError 异常。

read(num)

返回从当前文件位置开始最多包含 num 个字节的字符串; 文件位置更新为指向返回的字节之后。

read_byte()

返回包含当前文件位置字符的长度为 1 的字符串,并将文件位置向前移动 1。

readline()

返回一行,从当前文件位置开始,直到下一个换行符。

resize(newsize)

调整地图和基础文件的大小(如果有)。 如果 mmap 是用 ACCESS_READ 或 ACCESS_COPY 创建的,调整地图大小将引发 TypeError 异常。

rfind(string[, start[, end]])

返回对象中找到子字符串 string 的最高索引,使得 string 包含在 [start, end 范围内]。 可选参数 start 和 end 被解释为切片符号。 失败时返回 -1。

seek(pos[, whence])

设置文件的当前位置。 whence 参数可选,默认为 os.SEEK_SET 或 0(绝对文件定位); 其他值是 os.SEEK_CUR 或 1(相对于当前位置搜索)和 os.SEEK_END 或 2(相对于文件末尾搜索)。

size()

返回文件的长度,可以大于内存映射区的大小。

tell()

返回文件指针的当前位置。

write(string)

将string中的字节写入内存文件指针当前位置; 文件位置更新为指向写入的字节之后。 如果 mmap 是用 ACCESS_READ 创建的,那么写入它会引发一个 TypeError 异常。

write_byte(byte)

将单字符串byte写入内存文件指针当前位置; 文件位置前进 1。 如果 mmap 是用 ACCESS_READ 创建的,那么写入它会引发一个 TypeError 异常。