mmap --- 內(nèi)存映射文件支持?


內(nèi)存映射文件對(duì)象的行為既像 bytearray 又像 文件對(duì)象。 你可以在大部分接受 bytearray 的地方使用 mmap 對(duì)象;例如,你可以使用 re 模塊來搜索一個(gè)內(nèi)存映射文件。 你也可以通過執(zhí)行 obj[index] = 97 來修改單個(gè)字節(jié),或者通過對(duì)切片賦值來修改一個(gè)子序列: obj[i1:i2] = b'...'。 你還可以在文件的當(dāng)前位置開始讀取和寫入數(shù)據(jù),并使用 seek() 前往另一個(gè)位置。

內(nèi)存映射文件是由 mmap 構(gòu)造函數(shù)創(chuàng)建的,其在 Unix 和 Windows 上是不同的。 無論哪種情況,你都必須為一個(gè)打開的文件提供文件描述符以進(jìn)行更新。 如果你希望映射一個(gè)已有的 Python 文件對(duì)象,請(qǐng)使用該對(duì)象的 fileno() 方法來獲取 fileno 參數(shù)的正確值。 否則,你可以使用 os.open() 函數(shù)來打開這個(gè)文件,這會(huì)直接返回一個(gè)文件描述符(結(jié)束時(shí)仍然需要關(guān)閉該文件)。

備注

如果要為可寫的緩沖文件創(chuàng)建內(nèi)存映射,則應(yīng)當(dāng)首先 flush() 該文件。 這確保了對(duì)緩沖區(qū)的本地修改在內(nèi)存映射中可用。

對(duì)于 Unix 和 Windows 版本的構(gòu)造函數(shù),可以將 access 指定為可選的關(guān)鍵字參數(shù)。 access 接受以下四個(gè)值之一: ACCESS_READ , ACCESS_WRITEACCESS_COPY 分別指定只讀,直寫或?qū)憰r(shí)復(fù)制內(nèi)存,或 ACCESS_DEFAULT 推遲到 prot 。 access 可以在 Unix 和 Windows 上使用。如果未指定 access ,則 Windows mmap 返回直寫映射。這三種訪問類型的初始內(nèi)存值均取自指定的文件。向 ACCESS_READ 內(nèi)存映射賦值會(huì)引發(fā) TypeError 異常。 向 ACCESS_WRITE 內(nèi)存映射賦值會(huì)影響內(nèi)存和底層的文件。 向 ACCESS_COPY 內(nèi)存映射賦值會(huì)影響內(nèi)存,但不會(huì)更新底層的文件。

在 3.7 版更改: 添加了 ACCESS_DEFAULT 常量。

要映射匿名內(nèi)存,應(yīng)將 -1 作為 fileno 和 length 一起傳遞。

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

( Windows 版本) 映射被文件句柄 fileno 指定的文件的 length 個(gè)字節(jié),并創(chuàng)建一個(gè) mmap 對(duì)象。如果 length 大于當(dāng)前文件大小,則文件將擴(kuò)展為包含 length 個(gè)字節(jié)。如果 length0,則映射的最大長度為當(dāng)前文件大小。如果文件為空, Windows 會(huì)引發(fā)異常(你無法在Windows上創(chuàng)建空映射)。

如果 tagname 被指定且不是 None ,則是為映射提供標(biāo)簽名稱的字符串。 Windows 允許你對(duì)同一文件擁有許多不同的映射。如果指定現(xiàn)有標(biāo)簽的名稱,則會(huì)打開該標(biāo)簽,否則將創(chuàng)建該名稱的新標(biāo)簽。如果省略此參數(shù)或設(shè)置為 None ,則創(chuàng)建的映射不帶名稱。避免使用 tag 參數(shù)將有助于使代碼在Unix和Windows之間可移植。

offset 可以被指定為非負(fù)整數(shù)偏移量。 mmap 引用將相對(duì)于從文件開頭的偏移。 offset 默認(rèn)為0。 offeset 必須是 ALLOCATIONGRANULARITY 的倍數(shù)。

引發(fā)一個(gè) 審計(jì)事件 mmap.__new__ 附帶參數(shù) fileno, length, access, offset。

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

(Unix 版本) 映射文件描述符 fileno 指定的文件的 length 個(gè)字節(jié),并返回一個(gè) mmap 對(duì)象。如果 length0 ,則當(dāng)調(diào)用 mmap 時(shí),映射的最大長度將為文件的當(dāng)前大小。

flags 指明映射的性質(zhì)。 MAP_PRIVATE 會(huì)創(chuàng)建私有的寫入時(shí)拷貝映射,因此對(duì) mmap 對(duì)象內(nèi)容的修改將為該進(jìn)程所私有。 而 MAP_SHARED 會(huì)創(chuàng)建與其他映射同一文件區(qū)域的進(jìn)程所共享的映射。 默認(rèn)值為 MAP_SHARED。 某些系統(tǒng)還具有額外的可用旗標(biāo),完整列表會(huì)在 MAP_* 常量 中指明。

如果指明了 prot,它將給出所需的內(nèi)存保護(hù)方式;最有用的兩個(gè)值是 PROT_READPROT_WRITE,分別指明頁面為可讀或可寫。 prot 默認(rèn)為 PROT_READ | PROT_WRITE。

可以指定 access 作為替代 flagsprot 的可選關(guān)鍵字形參。 同時(shí)指定 flags, protaccess 將導(dǎo)致錯(cuò)誤。 請(qǐng)參閱上文中 access 的描述了解有關(guān)如何使用此形參的信息。

offset 可以被指定為非負(fù)整數(shù)偏移量。 mmap 引用將相對(duì)于從文件開頭的偏移。 offset 默認(rèn)為 0。 offset 必須是 ALLOCATIONGRANULARITY 的倍數(shù),它在 Unix 系統(tǒng)上等價(jià)于 PAGESIZE。

To ensure validity of the created memory mapping the file specified by the descriptor fileno is internally automatically synchronized with physical backing store on macOS and OpenVMS.

這個(gè)例子演示了使用 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 新版功能: 上下文管理器支持。

下面的例子演示了如何創(chuàng)建一個(gè)匿名映射并在父進(jìn)程和子進(jìn)程之間交換數(shù)據(jù)。:

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()

引發(fā)一個(gè) 審計(jì)事件 mmap.__new__ 附帶參數(shù) fileno, length, access, offset。

映射內(nèi)存的文件對(duì)象支持以下方法:

close()?

關(guān)閉 mmap。 后續(xù)調(diào)用該對(duì)象的其他方法將導(dǎo)致引發(fā) ValueError 異常。 此方法將不會(huì)關(guān)閉打開的文件。

closed?

如果文件已關(guān)閉則返回 True

3.2 新版功能.

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

返回子序列 sub 在對(duì)象內(nèi)被找到的最小索引號(hào),使得 sub 被包含在 [start, end] 范圍中。 可選參數(shù) startend 會(huì)被解讀為切片表示法。 如果未找到則返回 -1。

在 3.5 版更改: 現(xiàn)在接受可寫的 字節(jié)類對(duì)象。

flush([offset[, size]])?

將對(duì)文件的內(nèi)存副本的修改刷新至磁盤。 如果不使用此調(diào)用則無法保證在對(duì)象被銷毀前將修改寫回存儲(chǔ)。 如果指定了 offsetsize,則只將對(duì)指定范圍內(nèi)字節(jié)的修改刷新至磁盤;在其他情況下,映射的全部范圍都會(huì)被刷新。 offset 必須為 PAGESIZEALLOCATIONGRANULARITY 的倍數(shù)。

返回 None 以表示成功。 當(dāng)調(diào)用失敗時(shí)將引發(fā)異常。

在 3.8 版更改: 在之前版本中,成功時(shí)將返回非零值;在 Windows 下當(dāng)發(fā)生錯(cuò)誤時(shí)將返回零。 在 Unix 下 成功時(shí)將返回零值;當(dāng)發(fā)生錯(cuò)誤時(shí)將引發(fā)異常。

madvise(option[, start[, length]])?

將有關(guān)內(nèi)存區(qū)域的建議 option 發(fā)送至內(nèi)核,從 start 開始擴(kuò)展 length 個(gè)字節(jié)。 option 必須為系統(tǒng)中可用的 MADV_* 常量 之一。 如果省略 startlength,則會(huì)包含整個(gè)映射。 在某些系統(tǒng)中(包括 Linux),start 必須為 PAGESIZE 的倍數(shù)。

可用性: 具有 madvise() 系統(tǒng)調(diào)用的系統(tǒng)。

3.8 新版功能.

move(dest, src, count)?

將從偏移量 src 開始的 count 個(gè)字節(jié)拷貝到目標(biāo)索引號(hào) dest。 如果 mmap 創(chuàng)建時(shí)設(shè)置了 ACCESS_READ,則調(diào)用 move 將引發(fā) TypeError 異常。

read([n])?

返回一個(gè) bytes,其中包含從當(dāng)前文件位置開始的至多 n 個(gè)字節(jié)。 如果參數(shù)省略,為 None 或負(fù)數(shù),則返回從當(dāng)前文件位置開始直至映射結(jié)尾的所有字節(jié)。 文件位置會(huì)被更新為返回字節(jié)數(shù)據(jù)之后的位置。

在 3.3 版更改: 參數(shù)可被省略或?yàn)?None

read_byte()?

將當(dāng)前文件位置上的一個(gè)字節(jié)以整數(shù)形式返回,并讓文件位置前進(jìn) 1。

readline()?

返回一個(gè)單獨(dú)的行,從當(dāng)前文件位置開始直到下一個(gè)換行符。 文件位置會(huì)被更新為返回字節(jié)數(shù)據(jù)之后的位置。

resize(newsize)?

改變映射以及下層文件的大小,如果存在的話。 如果 mmap 創(chuàng)建時(shí)設(shè)置了 ACCESS_READACCESS_COPY,則改變映射大小將引發(fā) TypeError 異常。

On Windows: Resizing the map will raise an OSError if there are other maps against the same named file. Resizing an anonymous map (ie against the pagefile) will silently create a new map with the original data copied over up to the length of the new size.

在 3.11 版更改: Correctly fails if attempting to resize when another map is held Allows resize against an anonymous map on Windows

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

返回子序列 sub 在對(duì)象內(nèi)被找到的最大索引號(hào),使得 sub 被包含在 [start, end] 范圍中。 可選參數(shù) startend 會(huì)被解讀為切片表示法。 如果未找到則返回 -1。

在 3.5 版更改: 現(xiàn)在接受可寫的 字節(jié)類對(duì)象。

seek(pos[, whence])?

設(shè)置文件的當(dāng)前位置。 whence 參數(shù)為可選項(xiàng)并且默認(rèn)為 os.SEEK_SET0 (絕對(duì)文件定位);其他值還有 os.SEEK_CUR1 (相對(duì)當(dāng)前位置查找) 和 os.SEEK_END2 (相對(duì)文件末尾查找)。

size()?

返回文件的長度,該數(shù)值可以大于內(nèi)存映射區(qū)域的大小。

tell()?

返回文件指針的當(dāng)前位置。

write(bytes)?

bytes 中的字節(jié)數(shù)據(jù)寫入文件指針當(dāng)前位置的內(nèi)存并返回寫入的字節(jié)總數(shù) (一定不小于 len(bytes),因?yàn)槿绻麑懭胧?,將?huì)引發(fā) ValueError)。 在字節(jié)數(shù)據(jù)被寫入后文件位置將會(huì)更新。 如果 mmap 創(chuàng)建時(shí)設(shè)置了 ACCESS_READ,則向其寫入將引發(fā) TypeError 異常。

在 3.5 版更改: 現(xiàn)在接受可寫的 字節(jié)類對(duì)象

在 3.6 版更改: 現(xiàn)在會(huì)返回寫入的字節(jié)總數(shù)。

write_byte(byte)?

將整數(shù)值 byte 寫入文件指針當(dāng)前位置的內(nèi)存;文件位置前進(jìn) 1。 如果 mmap 創(chuàng)建時(shí)設(shè)置了 ACCESS_READ,則向其寫入將引發(fā) TypeError 異常。

MADV_* 常量?

mmap.MADV_NORMAL?
mmap.MADV_RANDOM?
mmap.MADV_SEQUENTIAL?
mmap.MADV_WILLNEED?
mmap.MADV_DONTNEED?
mmap.MADV_REMOVE?
mmap.MADV_DONTFORK?
mmap.MADV_DOFORK?
mmap.MADV_HWPOISON?
mmap.MADV_MERGEABLE?
mmap.MADV_UNMERGEABLE?
mmap.MADV_SOFT_OFFLINE?
mmap.MADV_HUGEPAGE?
mmap.MADV_NOHUGEPAGE?
mmap.MADV_DONTDUMP?
mmap.MADV_DODUMP?
mmap.MADV_FREE?
mmap.MADV_NOSYNC?
mmap.MADV_AUTOSYNC?
mmap.MADV_NOCORE?
mmap.MADV_CORE?
mmap.MADV_PROTECT?
mmap.MADV_FREE_REUSABLE?
mmap.MADV_FREE_REUSE?

這些選項(xiàng)可被傳給 mmap.madvise()。 不是每個(gè)選項(xiàng)都存在于每個(gè)系統(tǒng)中。

可用性: 具有 madvise() 系統(tǒng)調(diào)用的系統(tǒng)。

3.8 新版功能.

MAP_* 常量?

mmap.MAP_SHARED?
mmap.MAP_PRIVATE?
mmap.MAP_DENYWRITE?
mmap.MAP_EXECUTABLE?
mmap.MAP_ANON?
mmap.MAP_ANONYMOUS?
mmap.MAP_POPULATE?
mmap.MAP_STACK?

這些是可被傳給 mmap.mmap() 的各種旗標(biāo)。 請(qǐng)注意某些選項(xiàng)在某些系統(tǒng)上可能不存在。

在 3.10 版更改: 增加了 MAP_POPULATE 常量。

3.11 新版功能: Added MAP_STACK constant.