# 35.9. `fcntl` - `fcntl`和`ioctl`系统调用

该模块对文件描述器执行文件控制和I / O控制。它是`fcntl()`和`ioctl()` Unix例程的接口。有关这些调用的完整说明，请参阅fcntl（2）和ioctl（2） Unix手册页。

该模块中的所有函数都接受一个文件描述器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()`函数相同，只是参数处理更复杂。

  请求参数限制为可以容纳32位的值。用作请求参数的其他常用常量可在`termios`模块中找到，其名称与相关C头文件中使用的相同。

  The parameter arg can be one of an integer, an object supporting the read-only buffer interface (like `bytes`) or an object supporting the read-write buffer interface (like `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上执行锁操作操作（也接受提供`fileno()`方法的文件对象）。有关详细信息，请参阅Unix手册flock（2）。（在某些系统上，使用`fcntl()`来模拟此函数。）

  如果`flock()`失败，则会引发`OSError`异常。

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

  这本质上是`fcntl()`锁定调用的包装。fd是要锁定或解锁的文件的描述器，cmd是以下值之一：

  - `LOCK_UN` - 解锁
  - `LOCK_SH` - 获取共享锁
  - `LOCK_EX` - 获取独占锁

  当cmd为`LOCK_SH`或`LOCK_EX`时，也可​​以与`LOCK_NB`进行位或运算以避免锁定获取时阻塞。如果使用`LOCK_NB`并且无法获取锁定，则会引发`OSError`，并且异常将将errno属性设置为`EACCES`或`EAGAIN`（取决于操作系统；对于可移植性，请检查两个值）。在至少某些系统上，只有当文件描述器引用一个打开的写入文件时，才能使用`LOCK_EX`。

  len是要锁定的字节数，start是锁定开始的字节偏移量，相对于whence和whence 与`io.IOBase.seek()`一样，具体为：

  - `0` - 相对于文件的开头（`os.SEEK_SET`）
  - `1` - 相对于当前缓冲位置（`os.SEEK_CUR`）
  - `2` - 相对于文件结尾（`os.SEEK_END`）

  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`
  If the locking flags `O_SHLOCK` and `O_EXLOCK` are present in the `os` module (on BSD only), the `os.open()` function provides an alternative to the `lockf()` and `flock()` functions.