fcntl —— 系統調用 fcntlioctl?


本模塊基于文件描述符來進行文件控制和 I/O 控制。它是 Unix 系統調用 fcntl()ioctl() 的接口。關于這些調用的完整描述,請參閱 Unix 手冊的 fcntl(2)ioctl(2) 頁面。

本模塊的所有函數都接受文件描述符 fd 作為第一個參數。可以是一個整數形式的文件描述符,比如 sys.stdin.fileno() 的返回結果,或為 io.IOBase 對象,比如 sys.stdin 提供一個 fileno(),可返回一個真正的文件描述符。

在 3.3 版更改: 本模塊的操作以前觸發的是 IOError,現在則會觸發 OSError

這個模塊定義了以下函數:

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

對文件描述符 fd 執行 cmd 操作(能夠提供 fileno() 方法的文件對象也可以接受)。 cmd 可用的值與操作系統有關,在 fcntl 模塊中可作為常量使用,名稱與相關 C 語言頭文件中的一樣。參數 arg 可以是整數或 bytes 對象。若為整數值,則本函數的返回值是 C 語言 fcntl() 調用的整數返回值。若為字節串,則其代表一個二進制結構,比如由 struct.pack() 創建的數據。該二進制數據將被復制到一個緩沖區,緩沖區地址傳給 C 調用 fcntl()。調用成功后的返回值位于緩沖區內,轉換為一個 bytes 對象。返回的對象長度將與 arg 參數的長度相同。上限為 1024 字節。如果操作系統在緩沖區中返回的信息大于 1024 字節,很可能導致內存段沖突,或更為不易察覺的數據錯誤。

如果 fcntl() 調用失敗,會觸發 OSError

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

本函數與 fcntl() 函數相同,只是參數的處理更加復雜。

request 參數的上限是 32位。termios 模塊中包含了可用作 request 參數其他常量,名稱與相關 C 頭文件中定義的相同。

參數 arg 可為整數、支持只讀緩沖區接口的對象(如 bytes )或支持讀寫緩沖區接口的對象(如 bytearray )。

除了最后一種情況,其他情況下的行為都與 fcntl() 函數一樣。

如果傳入的是個可變緩沖區,那么行為就由 mutate_flag 參數決定。

如果為 False,緩沖區的可變性將被忽略,行為與只讀緩沖區一樣,只是沒有了上述 1024 字節的上限——只要傳入的緩沖區能容納操作系統放入的數據即可。

如果 mutate_flag 為 True(默認值),那么緩沖區(實際上)會傳給底層的 系統調用 ioctl() ,其返回代碼則會回傳給調用它的 Python,而緩沖區的新數據則反映了 ioctl() 的運行結果。這里做了一點簡化,因為若是給出的緩沖區少于 1024 字節,首先會被復制到一個 1024 字節長的靜態緩沖區再傳給 ioctl() ,然后把結果復制回給出的緩沖區去。

如果 ioctl() 調用失敗,則會觸發 OSError 異常。

舉個例子:

>>> 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])
fcntl.flock(fd, operation)?

在文件描述符 fd 上執行加鎖操作 operation (也接受能提供 fileno() 方法的文件對象)。 詳見 Unix 手冊 flock(2)。 (在某些系統中,此函數是用 fcntl() 模擬出來的。)

如果 flock() 調用失敗,就會觸發 OSError 異常。

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

This is essentially a wrapper around the fcntl() locking calls. fd is the file descriptor of the file to lock or unlock, and cmd is one of the following values:

  • LOCK_UN ——解鎖

  • LOCK_SH —— 獲取一個共享鎖

  • LOCK_EX —— 獲取一個獨占鎖

如果 cmdLOCK_SHLOCK_EX,則還可以與 LOCK_NB 進行按位或運算,以避免在獲取鎖時出現阻塞。 如果用了 LOCK_NB,無法獲取鎖時將觸發 OSError,此異常的 errno 屬性將被設為 EACCESEAGAIN (視操作系統而定;為了保證可移植性,請檢查這兩個值)。 至少在某些系統上,只有當文件描述符指向需要寫入而打開的文件時,才可以使用 LOCK_EX

len 是要鎖定的字節數,start 是自 whence 開始鎖定的字節偏移量,whenceio.IOBase.seek() 的定義一樣。

start 的默認值為 0,表示從文件起始位置開始。len 的默認值是 0,表示加鎖至文件末尾。 whence 的默認值也是 0。

示例(都是運行于符合 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() 函數的替代方案。