mmap --- 記憶體對映檔案的支援


可用性: not WASI.

此模組在 WebAssembly 平台上不起作用或無法使用。更多資訊請參閱 WebAssembly 平台。

記憶體對映檔案物件 (memory-mapped file objects) 的行為類似於 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_READ、ACCESS_WRITE 或 ACCESS_COPY 分別用於指定唯讀、直寫 (write-through) 或寫入時複製 (copy-on-write) 記憶體,或 ACCESS_DEFAULT 以遵從 prot。access 在 Unix 和 Windows 上都可以使用。如果未指定 access,Windows 的 mmap 會回傳直寫對映。三種存取類型的初始記憶體值都是取自指定的檔案。對 ACCESS_READ 記憶體對映進行賦值會引發 TypeError 例外。對 ACCESS_WRITE 記憶體對映進行賦值會同時影響記憶體和底層檔案。對 ACCESS_COPY 記憶體對映進行賦值會影響記憶體,但不會改變底層檔案。

在 3.7 版的變更: 新增 ACCESS_DEFAULT 常數。

要對映匿名記憶體,應將 -1 與長度一起作為 fileno 傳入。

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

(Windows 版本) 從檔案控制代碼 (file handle) fileno 指定的檔案來對映 length 個位元組,並建立一個 mmap 物件。如果 length 大於檔案目前的大小,檔案會被擴充為能夠包含 length 個位元組。如果 length 為 0,對映的最大長度就是檔案目前的大小,但如果檔案為空,Windows 會引發例外(因無法在 Windows 上建立空白的對映)。

若有指定 tagname 且不為 None,則其為給定對映的標籤名稱字串。Windows 允許你對同一個檔案設定許多不同的對映。如果你指定了一個現有標籤名稱,該標籤就會被開啟,否則會建立一個具有此名稱的新標籤。如果省略此參數或為 None,對映會在沒有名稱的情況下建立。避免使用 tagname 參數將有助於保持你的程式碼在 Unix 和 Windows 之間的可移植性。

offset 可以指定為非負整數偏移量。mmap 的參照會是相對於從檔案開頭算起之偏移量。offset 預設為 0。offset 必須是 ALLOCATIONGRANULARITY 的倍數。

引發一個附帶引數 fileno、length、access、offset 的稽核事件 mmap.__new__。

class mmap.mmap(fileno, length, flags=MAP_SHARED, prot=PROT_WRITE | PROT_READ, access=ACCESS_DEFAULT, offset=0, *, trackfd=True)

(Unix 版本) 從檔案描述器 fileno 指定的檔案對映 length 個位元組,並回傳一個 mmap 物件。如果 length 為 0,對映的最大長度將是呼叫 mmap 時檔案的目前大小。

flags 指定對映的性質。MAP_PRIVATE 會建立私有的寫入時複製對映,因此對 mmap 物件內容的變更將僅限於此行程,而 MAP_SHARED 會建立與所有其他對映相同檔案區域之行程共享的對映。預設值為 MAP_SHARED。某些系統有額外的可用旗標,完整列表請參閱 MAP_* 常數。

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。

如果 trackfd 為 False,由 fileno 指定的檔案描述器將不會被複製,且產生的 mmap 物件將不會與對映的底層檔案關聯。這意味著 size() 和 resize() 方法會失敗。此模式對於限制開啟的檔案描述器數量很有用。

為了確保建立的記憶體對映有效,在 macOS 上由描述器 fileno 指定的檔案會在內部自動與實體備份儲存同步。

在 3.13 版的變更: 新增 trackfd 參數。

這個範例示範了使用 mmap 的簡單方式:

import mmap

# 寫入一個簡單的範例檔案
with open("hello.txt", "wb") as f:
    f.write(b"Hello Python!\n")

with open("hello.txt", "r+b") as f:
    # 對映檔案到記憶體,size 0 表示整個檔案
    mm = mmap.mmap(f.fileno(), 0)
    # 透過標準檔案方法讀取內容
    print(mm.readline())  # 印出 b"Hello Python!\n"
    # 透過切片標記法讀取內容
    print(mm[:5])  # 印出 b"Hello"
    # 使用切片標記法更新內容;
    # 注意新內容必須有相同的大小
    mm[6:] = b" world!\n"
    # ... 然後再次使用標準檔案方法讀取
    mm.seek(0)
    print(mm.readline())  # 印出 b"Hello  world!\n"
    # 關閉對映
    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:  # 在子行程中
    mm.seek(0)
    print(mm.readline())

    mm.close()

引發一個附帶引數 fileno、length、access、offset 的稽核事件 mmap.__new__。

記憶體對映檔案物件支援以下方法:

close()

關閉 mmap。後續對物件其他方法的呼叫將導致 ValueError 例外被引發。這不會關閉已開啟的檔案。

closed

若檔案已關閉則回傳 True。

在 3.2 版被加入.

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

回傳物件中找到子序列 sub 的最小索引,使得 sub 包含在範圍 [start, end] 中。可選引數 start 和 end 的直譯方式與切片標記法相同。失敗時回傳 -1。

在 3.5 版的變更: 現在接受可寫入的類位元組物件。

flush()
flush(offset, size, /)

將對檔案之記憶體內副本 (in-memory copy) 所做的變更給排清 (flush) 回磁碟。若不使用此呼叫,則無法保證在物件被銷毀之前變更會被寫回。如果指定了 offset 和 size,則只有給定位元組範圍的變更會被排清到磁碟;否則會排清整個對映範圍。offset 必須是 PAGESIZE 或 ALLOCATIONGRANULARITY 的倍數。

回傳 None 表示成功。呼叫失敗時會引發例外。

在 3.8 版的變更: 以前在 Windows 上成功時會回傳非零值,錯誤時回傳零。在 Unix 上成功時回傳零值,錯誤時引發例外。

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

向核心 (kernel) 發送關於從 start 開始並延伸 length 個位元組之記憶體區域的建議 option。option 必須是系統上可用的 MADV_* 常數 之一。如果省略 start 和 length,則會涵蓋整個對映。在某些系統(包括 Linux)上,start 必須是 PAGESIZE 的倍數。

可用性:具有 madvise() 系統呼叫的系統。

在 3.8 版被加入.

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)

調整對映和底層檔案(如果有的話)的大小。

調整以 access 為 ACCESS_READ 或 ACCESS_COPY 建立的對映大小會引發 TypeError 例外。調整以 trackfd 設定為 False 建立的對映大小會引發 ValueError 例外。

在 Windows 上:如果有其他對映指向同一個具名檔案,調整對映大小會引發 OSError。調整匿名對映(即指向分頁檔案)的大小會靜默地建立一個新對映,並將原始資料複製到新大小的長度。

在 3.11 版的變更: 當持有另一個對映時嘗試調整大小會正確失敗;在 Windows 上允許對匿名對映調整大小

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

回傳物件中找到子序列 sub 的最大索引,使得 sub 包含在範圍 [start, end] 中。可選引數 start 和 end 的直譯方式與切片標記法相同。失敗時回傳 -1。

在 3.5 版的變更: 現在接受可寫入的類位元組物件。

seek(pos[, whence])

設定檔案的目前位置。whence 引數是可選的,預設為 os.SEEK_SET 或 0(絕對檔案定位);其他值為 os.SEEK_CUR 或 1(相對於目前位置的定位)和 os.SEEK_END 或 2(相對於檔案結尾的定位)。

在 3.13 版的變更: 回傳新的絕對位置而非 None。

seekable()

回傳檔案是否支援定位 (seeking),回傳值永遠為 True。

在 3.13 版被加入.

size()

回傳檔案的長度,該長度可以大於記憶體對映區域的大小。

tell()

回傳檔案指標的目前位置。

write(bytes)

將 bytes 中的位元組寫入檔案指標目前位置的記憶體,並回傳寫入的位元組數(絕不會少於 len(bytes),因為如果寫入失敗,會引發 ValueError)。檔案位置會被更新為指向寫入的位元組之後。如果 mmap 是以 ACCESS_READ 建立的,則對其寫入會引發 TypeError 例外。

在 3.5 版的變更: 現在接受可寫入的類位元組物件。

在 3.6 版的變更: 現在會回傳寫入的位元組數。

write_byte(byte)

將整數 byte 寫入檔案指標目前位置的記憶體;檔案位置會前進 1。如果 mmap 是以 ACCESS_READ 建立的,則對其寫入會引發 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

這些選項可以傳遞給 mmap.madvise()。並非每個選項都會出現在每個系統上。

可用性:具有 madvise() 系統呼叫的系統。

在 3.8 版被加入.

MAP_* 常數

mmap.MAP_SHARED
mmap.MAP_PRIVATE
mmap.MAP_32BIT
mmap.MAP_ALIGNED_SUPER
mmap.MAP_ANON
mmap.MAP_ANONYMOUS
mmap.MAP_CONCEAL
mmap.MAP_DENYWRITE
mmap.MAP_EXECUTABLE
mmap.MAP_HASSEMAPHORE
mmap.MAP_JIT
mmap.MAP_NOCACHE
mmap.MAP_NOEXTEND
mmap.MAP_NORESERVE
mmap.MAP_POPULATE
mmap.MAP_RESILIENT_CODESIGN
mmap.MAP_RESILIENT_MEDIA
mmap.MAP_STACK
mmap.MAP_TPRO
mmap.MAP_TRANSLATED_ALLOW_EXECUTE
mmap.MAP_UNIX03

這些是可以傳遞給 mmap.mmap() 的各種旗標。MAP_ALIGNED_SUPER 僅在 FreeBSD 上可用,而 MAP_CONCEAL 僅在 OpenBSD 上可用。請注意,某些選項可能不會出現在某些系統上。

在 3.10 版的變更: 新增 MAP_POPULATE 常數。

在 3.11 版被加入: 新增 MAP_STACK 常數。

在 3.12 版被加入: 新增 MAP_ALIGNED_SUPER 和 MAP_CONCEAL 常數。