Skip to main content

18.9. mmap —内存映射文件支持


内存映射文件对象的行为像 bytearray 和像 文件对象。你可以在大多数需要 bytearray 的地方使用mmap对象;例如,您可以使用 re 模块搜索内存映射文件。您也可以通过执行 obj[index] = 97 更改单个字节,或通过分配到切片来更改子序列:obj[i1:i2] = b'...'。您还可以从当前文件位置开始读取和写入数据,并且 seek() 通过文件到不同位置。

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

注解

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

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

要映射匿名内存,-1应该作为fileno与长度一起传递。

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

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

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

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

class mmap.mmap(fileno, length, flags=MAP_SHARED, prot=PROT_WRITE|PROT_READ, access=ACCESS_DEFAULT[, offset])

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

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

prot,如果指定,给出所需的存储器保护;两个最有用的值是 PROT_READPROT_WRITE,以指定可以读取或写入页面。 prot 默认为 PROT_READ | PROT_WRITE

可以指定 access 来代替 flagsprot 作为可选的关键字参数。指定 flagsprotaccess 是错误的。有关如何使用此参数的信息,请参阅上述 access 的说明。

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

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

此示例显示了使用 mmap 的一种简单方法:

import mmap

# write a simple example file
with open("hello.txt", "wb") as f:
    f.write(b"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 b"Hello Python!\n"
    # read content via slice notation
    print(mm[:5])  # prints b"Hello"
    # update content using slice notation;
    # note that new content must have same size
    mm[6:] = b" world!\n"
    # ... and read again using standard file methods
    mm.seek(0)
    print(mm.readline())  # prints b"Hello  world!\n"
    # close the map
    mm.close()

mmap 也可以用作 with 语句中的上下文管理器。:

import mmap

with mmap.mmap(-1, 13) as mm:
    mm.write(b"Hello world!")

3.2 新版功能: 上下文管理器支持。

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

import mmap
import os

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

pid = os.fork()

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

    mm.close()

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

close()

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

closed

True 如果文件关闭。

3.2 新版功能.

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

返回找到子序列 sub 的对象中的最低索引,使得 sub 包含在范围[startend]中。可选参数 startend 解释为切片表示法。失败时返回 -1

在 3.5 版更改: 可写 bytes-like object 现已被接受。

flush([offset[, size]])

将对文件的内存中副本所做的更改刷新回磁盘。不使用此调用,不能保证在对象被销毁之前写回更改。如果指定了 offsetsize,则只将对给定字节范围的更改刷新到磁盘;否则,映射的整个范围被刷新。

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

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

move(dest, src, count)

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

read([n])

返回从当前文件位置开始包含最多 n 个字节的 bytes。如果省略参数 None 或负数,则将所有字节从当前文件位置返回到映射结束。文件位置更新为指向返回的字节之后。

在 3.3 版更改: 参数可以省略或 None

read_byte()

以当前文件位置作为整数返回一个字节,并将文件位置前移1。

readline()

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

resize(newsize)

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

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

返回找到子序列 sub 的对象中的最高索引,使得 sub 包含在范围[startend]中。可选参数 startend 解释为切片表示法。失败时返回 -1

在 3.5 版更改: 可写 bytes-like object 现已被接受。

seek(pos[, whence])

设置文件的当前位置。 whence 参数是可选的,默认为 os.SEEK_SET0 (绝对文件定位);其他值是 os.SEEK_CUR1 (相对于当前位置寻找)和 os.SEEK_END2 (相对于文件结尾寻找)。

size()

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

tell()

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

write(bytes)

bytes 中的字节写入到文件指针的当前位置的存储器中,并返回写入的字节数(从不小于 len(bytes),因为如果写入失败,则会引发 ValueError)。文件位置更新为指向写入的字节。如果mmap是用 ACCESS_READ 创建的,那么写入它将引发 TypeError 异常。

在 3.5 版更改: 可写 bytes-like object 现已被接受。

在 3.6 版更改: 现在返回写入的字节数。

write_byte(byte)

将整数 byte 写入文件指针当前位置的内存;文件位置由 1 提前。如果mmap是用 ACCESS_READ 创建的,那么写入它将引发 TypeError 异常。