fcntl --- fcntlioctl 系統呼叫


此模組對檔案描述符執行檔案和 I/O 控制。它是 fcntl()ioctl() Unix 例程的介面。有關完整的詳細資訊,請參閱 fcntl(2)ioctl(2) Unix 手冊頁。

可用性: Unix,不包括 WASI。

此模組中的所有函式都接受一個檔案描述符 fd 作為其第一個引數。這可以是一個整數檔案描述符,例如 sys.stdin.fileno() 返回的值,也可以是一個 io.IOBase 物件,例如 sys.stdin 本身,它提供了一個返回真實檔案描述符的 fileno() 方法。

在 3.3 版更改: 此模組中的操作過去會引發 IOError,現在則會引發 OSError

在 3.8 版更改: fcntl 模組現在包含用於密封 os.memfd_create() 檔案描述符的 F_ADD_SEALSF_GET_SEALSF_SEAL_* 常量。

在 3.9 版更改: 在 macOS 上,fcntl 模組公開了 F_GETPATH 常量,用於從檔案描述符獲取檔案路徑。在 Linux(>=3.15) 上,fcntl 模組公開了 F_OFD_GETLKF_OFD_SETLKF_OFD_SETLKW 常量,這些常量用於處理開啟檔案描述符鎖。

在 3.10 版更改: 在 Linux >= 2.6.11 上,fcntl 模組公開了 F_GETPIPE_SZF_SETPIPE_SZ 常量,它們分別允許檢查和修改管道的大小。

在 3.11 版更改: 在 FreeBSD 上,fcntl 模組公開了 F_DUP2FDF_DUP2FD_CLOEXEC 常量,它們允許複製一個檔案描述符,後者還會額外設定 FD_CLOEXEC 標誌。

在 3.12 版更改: 在 Linux >= 4.5 上,fcntl 模組公開了 FICLONEFICLONERANGE 常量,它們允許在某些檔案系統(例如 btrfs、OCFS2 和 XFS)上透過 reflinking 將一個檔案的資料與另一個檔案共享。此行為通常稱為“寫入時複製”(copy-on-write)。

在 3.13 版更改: 在 Linux >= 2.6.32 上,fcntl 模組公開了 F_GETOWN_EXF_SETOWN_EXF_OWNER_TIDF_OWNER_PIDF_OWNER_PGRP 常量,它們允許將 I/O 可用性訊號定向到特定的執行緒、程序或程序組。在 Linux >= 4.13 上,fcntl 模組公開了 F_GET_RW_HINTF_SET_RW_HINTF_GET_FILE_RW_HINTF_SET_FILE_RW_HINTRWH_WRITE_LIFE_* 常量,它們允許通知核心關於在給定 inode 或透過特定開啟檔案描述符上的寫入的相對預期壽命。在 Linux >= 5.1 和 NetBSD 上,fcntl 模組公開了用於 F_ADD_SEALSF_GET_SEALS 操作的 F_SEAL_FUTURE_WRITE 常量。在 FreeBSD 上,fcntl 模組公開了 F_READAHEADF_ISUNIONSTACKF_KINFO 常量。在 macOS 和 FreeBSD 上,fcntl 模組公開了 F_RDAHEAD 常量。在 NetBSD 和 AIX 上,fcntl 模組公開了 F_CLOSEM 常量。在 NetBSD 上,fcntl 模組公開了 F_MAXFD 常量。在 macOS 和 NetBSD 上,fcntl 模組公開了 F_GETNOSIGPIPEF_SETNOSIGPIPE 常量。

在 3.14 版更改: 在 Linux >= 6.1 上,fcntl 模組公開了 F_DUPFD_QUERY,用於查詢指向同一檔案的檔案描述符。

該模組定義了以下函式:

fcntl.fcntl(fd, cmd, arg=0, /)

對檔案描述符 fd 執行操作 cmd(也接受提供 fileno() 方法的檔案物件)。用於 cmd 的值是作業系統相關的,並在 fcntl 模組中作為常量提供,使用的名稱與相關 C 標頭檔案中的名稱相同。引數 arg 可以是整數值、類位元組物件或字串。arg 的型別和大小必須與相關 C 文件中指定的操作引數的型別和大小相匹配。

arg 是一個整數時,該函式返回 C fcntl() 呼叫的整數返回值。

當引數是類位元組物件時,它表示一個二進位制結構,例如由 struct.pack() 建立的結構。字串值會使用 UTF-8 編碼為二進位制。二進位制資料被複制到一個緩衝區,其地址被傳遞給 C fcntl() 呼叫。成功呼叫後的返回值是緩衝區的內容,轉換為 bytes 物件。返回物件的長度將與 arg 引數的長度相同。這被限制在 1024 位元組以內。

如果 fcntl() 呼叫失敗,則會引發 OSError

備註

如果 arg 的型別或大小與操作引數的型別或大小不匹配(例如,當期望一個指標時傳遞了一個整數,或者作業系統在緩衝區中返回的資訊大於 1024 位元組),這很可能會導致段錯誤或更細微的資料損壞。

觸發一個引數為 fd, cmd, arg審計事件 fcntl.fcntl

在 3.14 版更改: 增加了對任意類位元組物件的支援,而不僅是 bytes

fcntl.ioctl(fd, request, arg=0, mutate_flag=True, /)

此函式與 fcntl() 函式相同,只是引數處理更為複雜。

request 引數受限於能放入 32 位或 64 位的值,具體取決於平臺。其他可用作 request 引數的常量可以在 termios 模組中找到,其名稱與相關 C 標頭檔案中使用的名稱相同。

引數 arg 可以是一個整數、一個類位元組物件或一個字串。arg 的型別和大小必須與相關 C 文件中指定的操作引數的型別和大小相匹配。

如果 arg 不支援讀寫緩衝區介面,或者 mutate_flag 為 false,則其行為與 fcntl() 函式相同。

如果 arg 支援讀寫緩衝區介面(如 bytearray)並且 mutate_flag 為 true(預設值),那麼緩衝區(實際上)被傳遞給底層的 ioctl() 系統呼叫,後者的返回碼被傳回給呼叫它的 Python,並且緩衝區的新內容反映了 ioctl() 的操作。這是一個輕微的簡化,因為如果提供的緩衝區小於 1024 位元組長,它會首先被複制到一個 1024 位元組長的靜態緩衝區,然後該靜態緩衝區被傳遞給 ioctl(),並再被複制回提供的緩衝區。

如果 ioctl() 呼叫失敗,將引發 OSError 異常。

備註

如果 arg 的型別或大小與操作引數的型別或大小不匹配(例如,當期望一個指標時傳遞了一個整數,或者作業系統在緩衝區中返回的資訊大於 1024 位元組,或者可變類位元組物件的大小太小),這很可能會導致段錯誤或更細微的資料損壞。

一個例子:

>>> import array, fcntl, struct, termios, os
>>> os.getpgrp()
13341
>>> struct.unpack('h', fcntl.ioctl(0, termios.TIOCGPGRP, "  "))[0]
13341
>>> buf = array.array('h', [0])
>>> fcntl.ioctl(0, termios.TIOCGPGRP, buf, 1)
0
>>> buf
array('h', [13341])

觸發一個引數為 fd, request, arg審計事件 fcntl.ioctl

在 3.14 版更改: 在系統呼叫期間,GIL 總是被釋放。因 EINTR 而失敗的系統呼叫會自動重試。

fcntl.flock(fd, operation, /)

對檔案描述符 fd 執行鎖操作 operation(也接受提供 fileno() 方法的檔案物件)。詳情請參閱 Unix 手冊 flock(2)。(在某些系統上,此函式是使用 fcntl() 模擬的。)

如果 flock() 呼叫失敗,將引發 OSError 異常。

觸發一個引數為 fd, operation審計事件 fcntl.flock

fcntl.lockf(fd, cmd, len=0, start=0, whence=0, /)

這本質上是 fcntl() 鎖定呼叫的一個包裝器。fd 是要鎖定或解鎖的檔案的檔案描述符(也接受提供 fileno() 方法的檔案物件),而 cmd 是以下值之一:

fcntl.LOCK_UN

釋放一個現有的鎖。

fcntl.LOCK_SH

獲取一個共享鎖。

fcntl.LOCK_EX

獲取一個排他鎖。

fcntl.LOCK_NB

與任何其他三個 LOCK_* 常量進行按位或運算,以使請求非阻塞。

如果使用 LOCK_NB 且無法獲取鎖,將引發 OSError,並且異常的 errno 屬性將設定為 EACCESEAGAIN(取決於作業系統;為了可移植性,請檢查這兩個值)。在至少某些系統上,LOCK_EX 只能在檔案描述符指向一個以寫入模式開啟的檔案時使用。

len 是要鎖定的位元組數,start 是鎖開始的位元組偏移量,相對於 whence,而 whenceio.IOBase.seek() 一樣,具體為:

start 的預設值是 0,表示從檔案開頭開始。len 的預設值是 0,表示鎖定到檔案末尾。whence 的預設值也是 0。

觸發一個引數為 fd, cmd, len, start, whence審計事件 fcntl.lockf

示例(全部在 SVR4 相容系統上):

import struct, fcntl, os

f = open(...)
rv = fcntl.fcntl(f, fcntl.F_SETFL, os.O_NDELAY)

lockdata = struct.pack('hhllhh', fcntl.F_WRLCK, 0, 0, 0, 0, 0)
rv = fcntl.fcntl(f, fcntl.F_SETLKW, lockdata)

請注意,在第一個示例中,返回值變數 rv 將持有一個整數值;在第二個示例中,它將持有一個 bytes 物件。lockdata 變數的結構佈局是系統相關的——因此使用 flock() 呼叫可能更好。

參見

模組 os

如果 os 模組中存在鎖定標誌 O_SHLOCKO_EXLOCK(僅限 BSD),os.open() 函式為 lockf()flock() 函式提供了替代方案。