os模块篇(八)

文章目录

  • os.openpty()
  • os.pipe()
  • [os.pipe2(flags, /)](#os.pipe2(flags, /))
  • [os.posix_fallocate(fd, offset, len, /)](#os.posix_fallocate(fd, offset, len, /))
  • [os.posix_fadvise(fd, offset, len, advice, /)](#os.posix_fadvise(fd, offset, len, advice, /))
  • [os.pread(fd, n, offset, /)](#os.pread(fd, n, offset, /))
  • [os.posix_openpt(oflag, /)](#os.posix_openpt(oflag, /))
  • [os.preadv(fd, buffers, offset, flags=0, /)](#os.preadv(fd, buffers, offset, flags=0, /))
  • [os.ptsname(fd, /)](#os.ptsname(fd, /))
  • [os.pwrite(fd, str, offset, /)](#os.pwrite(fd, str, offset, /))
  • [os.pwritev(fd, buffers, offset, flags=0, /)](#os.pwritev(fd, buffers, offset, flags=0, /))

os.openpty()

os.openpty() 是 Python 的 os 模块中的一个函数,用于打开一个新的伪终端对(pseudo-terminal pair)。伪终端对通常用于实现像 shell 这样的交互式环境,它们允许一个程序(例如,一个 shell)作为终端的用户界面运行,而另一个程序(例如,一个 shell 执行的命令)可以像在一个真实的终端中运行一样接收和发送输入/输出。

os.openpty() 返回一个包含两个文件描述符的元组 (master_fd, slave_fd):

  • master_fd 是主设备(master device)的文件描述符,通常用于程序(如 shell)读取和写入,以接收从子设备(slave device)发送的数据并发送数据到子设备。
  • slave_fd 是子设备(slave device)的文件描述符,通常用于另一个程序(如 shell 执行的命令)读取和写入。

以下是一个使用 os.openpty() 的简单示例:

python 复制代码
import os
import sys

# 打开一个新的伪终端对
master_fd, slave_fd = os.openpty()

# 使用 os.ttyname() 可以得到与文件描述符相关联的设备名称
print("Master device:", os.ttyname(master_fd))
print("Slave device:", os.ttyname(slave_fd))

# 通常你会在这里 fork 一个子进程,并将 slave_fd 传递给子进程
# 子进程会将其用作其标准输入、输出和错误输出

# 关闭不再需要的文件描述符
os.close(master_fd)
os.close(slave_fd)

在上面的代码中,我们打开了一个新的伪终端对,并打印了主设备和子设备的名称。在实际应用中,你会在 os.openpty() 调用之后 fork 一个子进程,并将子设备的文件描述符传递给它。子进程可以将其用作其标准输入、输出和错误输出,从而允许它与主设备(通常由父进程控制)进行交互。

注意:在真实的使用场景中,你还需要处理诸如信号处理、进程间通信等额外的问题。此外,os.openpty() 在 Windows 上不可用;在 Windows 上,你可能需要使用其他机制(如 winpty)来实现类似的功能

os.pipe()

os.pipe() 是 Python 的 os 模块中的一个函数,它用于创建一个新的管道。管道是一种用于进程间通信的机制,允许一个进程向另一个进程发送数据。

os.pipe() 函数返回一个包含两个文件描述符的元组 (r, w):

  • r 是管道的读端文件描述符,用于从管道中读取数据。
  • w 是管道的写端文件描述符,用于向管道中写入数据。

当从一个进程向管道的写端写入数据时,这些数据可以被另一个进程从管道的读端读取。

下面是一个使用 os.pipe() 创建管道并进行进程间通信的简单示例:

python 复制代码
import os

# 创建一个管道
read_end, write_end = os.pipe()

# 创建一个子进程
pid = os.fork()

if pid == 0:  # 子进程
    # 关闭管道的写端
    os.close(write_end)

    # 从管道的读端读取数据
    data = os.read(read_end, 1024)
    print("Child process received:", data.decode())

    # 关闭管道的读端
    os.close(read_end)
    os._exit(0)
else:  # 父进程
    # 关闭管道的读端
    os.close(read_end)

    # 向管道的写端写入数据
    os.write(write_end, b"Hello from parent!")

    # 关闭管道的写端
    os.close(write_end)

    # 等待子进程结束
    os.wait()

在上面的示例中,父进程和子进程通过管道进行通信。父进程向管道的写端写入字符串 "Hello from parent!",而子进程从管道的读端读取这个字符串并打印出来。

需要注意的是,管道是在进程间进行通信的,而不是线程间。如果你需要在同一进程的多个线程之间进行通信,可能需要使用线程安全的队列或其他同步机制。

此外,管道是半双工的,即数据只能在一个方向上流动。如果你需要双向通信,可能需要使用两个管道,或者考虑使用其他进程间通信机制,如套接字(sockets)、命名管道(named pipes)或共享内存等。

os.pipe2(flags, /)

os.pipe2() 是 Python 3.3 版本中引入的一个函数,它是 os.pipe() 的一个扩展版本。os.pipe2() 提供了更多的选项来配置新创建的管道,通过传递一个标志参数 flags 来实现。

Flags 参数是一个整数,用于指定管道的一些属性。这个参数可以是一些预定义的常量,通过按位或(bitwise OR)操作组合在一起。这些常量通常定义在 <fcntl.h> 头文件中,但在 Python 中可以通过 os 模块访问。

以下是一些可能的 Flags 值(在 Python 中可能以 os.O_ 为前缀):

  • os.O_NONBLOCK: 设置管道为非阻塞模式。这意味着读取或写入管道时,如果没有数据可用或没有足够的空间来写入数据,操作将立即返回而不是阻塞。
  • os.O_CLOEXEC: 设置管道的文件描述符在 exec() 系列函数执行后自动关闭。这有助于防止文件描述符泄漏到新的进程中。

os.pipe2() 返回一个元组,其中包含两个文件描述符,分别是管道的读端和写端,类似于 os.pipe()。

下面是一个使用 os.pipe2() 的示例:

python 复制代码
import os

# 创建一个非阻塞的管道
flags = os.O_NONBLOCK
read_end, write_end = os.pipe2(Flags)

# 使用文件描述符进行读写操作
# 注意:因为设置了非阻塞模式,所以读写操作可能立即返回

os.pipe2() 的主要优势在于它允许你更精细地控制管道的行为,特别是在处理多进程或多线程的程序时,你可能需要确保文件描述符在适当的时机被正确关闭,或者希望管道以非阻塞模式运行。

需要注意的是,os.pipe2() 可能在一些旧的操作系统或 Python 版本中不可用。在这种情况下,你可以回退到使用 os.pipe() 并手动设置文件描述符的属性,例如使用 fcntl 模块来设置非阻塞模式。

os.posix_fallocate(fd, offset, len, /)

os.posix_fallocate() 是 Python 3.3 中引入的一个函数,它提供了一个在文件描述符上预分配文件空间的方法,而不需要实际写入任何数据。这个函数是 POSIX 系统(如 Linux 和 macOS)特有的,因此在非 POSIX 系统上可能不可用。

函数的参数如下:

  • fd:一个打开文件的文件描述符(通常是通过 os.open() 获得的)。
  • offset:开始预分配空间的偏移量(以字节为单位)。
  • len:要预分配的空间长度(以字节为单位)。

os.posix_fallocate() 会扩展或截断指定的文件,使其大小至少为 offset + len 字节。如果文件之前的大小小于这个值,那么该函数会在文件中添加额外的空间,但不会写入任何实际的数据。这可以用于提高文件操作的性能,尤其是在你知道文件最终将包含大量数据时。

这里有一个使用 os.posix_fallocate() 的例子:

python 复制代码
import os

# 打开一个文件,如果不存在则创建它
fd = os.open('example.dat', os.O_WRONLY | os.O_CREAT)

# 预分配 10 MiB 的空间
size = 10 * 1024 * 1024  # 10 MiB
os.posix_fallocate(fd, 0, size)

# 关闭文件描述符
os.close(fd)

在这个例子中,example.dat 文件将被创建(如果它之前不存在),并且其大小将被扩展为至少 10 MiB,即使实际上没有写入任何数据。

请注意,os.posix_fallocate() 只影响文件在磁盘上的大小,并不保证文件的物理磁盘块都被立即分配。实际的物理分配可能会延迟到文件第一次被写入时。此外,如果文件已经存在并且其大小大于指定的 offset + len,则该函数不会截断文件。如果需要截断文件,可以使用 os.ftruncate()。

os.posix_fadvise(fd, offset, len, advice, /)

os.posix_fadvise() 是 Python 的一个较低级别的系统调用接口,它用于向操作系统提供关于文件访问模式的建议,从而帮助操作系统优化文件访问性能。这个函数是 POSIX(Portable Operating System Interface)系统特有的,因此可能在非 POSIX 系统上不可用。

函数参数如下:

  • fd: 文件描述符,通常是通过 os.open() 或其他系统调用获得的。
  • offset: 开始提供建议的字节偏移量。
  • len: 提供建议的字节长度。
    8 advice: 一个整数,表示给出的建议类型。

advice 参数可以取以下预定义的值之一(这些值通常定义在 <fcntl.h> 头文件中,但在 Python 中可以通过 os 模块访问):

  • os.POSIX_FADV_NORMAL: 没有任何特殊的建议,文件访问遵循常规的文件系统缓存行为。
  • os.POSIX_FADV_RANDOM: 文件访问模式是随机的,文件系统应该避免缓存数据。
  • os.POSIX_FADV_SEQUENTIAL: 文件访问模式是顺序的,文件系统应该尽量缓存数据以优化连续读取。
  • os.POSIX_FADV_WILLNEED: 文件将在不久的将来被访问,文件系统应该预先加载数据到缓存中。
  • os.POSIX_FADV_DONTNEED: 文件在未来不会被访问,文件系统可以丢弃缓存中的数据。
  • os.POSIX_FADV_NOREUSE: 文件数据应该被缓存,但不应该被重新使用来优化其他文件的访问。

这些建议是非强制性的,操作系统可以选择忽略它们。但是,在知道文件访问模式的情况下,使用 os.posix_fadvise() 可以帮助操作系统做出更智能的缓存决策,从而提高文件访问性能。

下面是一个使用 os.posix_fadvise() 的简单示例:

python 复制代码
import os

# 打开一个文件
fd = os.open('example.dat', os.O_RDONLY)

# 假设我们即将顺序读取文件的前 1024 字节
offset = 0
length = 1024
advice = os.POSIX_FADV_SEQUENTIAL

# 提供建议
os.posix_fadvise(fd, offset, length, advice)

# 读取文件数据
data = os.read(fd, length)

# 关闭文件描述符
os.close(fd)

# 处理数据...

在这个例子中,我们告诉操作系统我们将要顺序读取文件的前 1024 字节,因此它可能会选择优化这个区域的缓存行为。当然,这个优化在实际应用中可能不会产生显著的影响,但它是一个可以使用的工具,尤其是在处理大文件或需要高性能文件访问的场景中。

os.pread(fd, n, offset, /)

os.pread(fd, n, offset) 是 Python 的一个系统调用接口,用于从文件描述符 fd 中读取数据,并从文件的 offset 偏移量开始读取 n 个字节。这个调用与普通的 os.read(fd, n) 调用不同,因为它不会受到文件描述符的当前文件位置的影响,也不会在读取后更新文件描述符的文件位置。

参数说明:

  • fd: 文件描述符,通常是通过 os.open() 或其他系统调用获得的。
  • n: 要读取的字节数。
  • offset: 从文件的哪个位置开始读取。这是一个绝对位置,而不是相对于当前文件位置的偏移量。

返回值是读取到的字节串(bytes),如果读取的字节数少于请求的 n 个字节,可能是因为文件结束或发生了错误。

os.pread() 常常用于需要精确控制文件读取位置的场景,例如当多个进程或线程需要读取文件的特定部分时,或者当你不希望 read 调用改变文件描述符的文件位置时。

下面是一个使用 os.pread() 的简单示例:

python 复制代码
import os

# 打开一个文件
fd = os.open('example.txt', os.O_RDONLY)

# 从文件的第10个字节开始读取10个字节
data = os.pread(fd, 10, 10)

# 处理读取到的数据
print(data)

# 关闭文件描述符
os.close(fd)

在这个例子中,os.pread() 从 example.txt 文件的第10个字节开始读取了10个字节的数据。即使文件描述符 fd 的当前文件位置在其他地方,os.pread() 也会精确地从这个指定的偏移量开始读取。

请注意,os.pread() 在非 POSIX 系统上可能不可用,或者可能需要使用不同的方法来达到相同的效果。在 POSIX 系统上,这个函数通常与 os.pwrite() 配对使用,后者用于从指定的偏移量开始写入数据到文件。

os.posix_openpt(oflag, /)

os.posix_openpt() 是 Python 的一个系统调用,它用于打开一个新的伪终端(pseudo-terminal,通常简称为 pty)的主设备(master device)。伪终端通常用于实现类似 shell 的交互环境,其中程序(如终端仿真器)通过主设备与从设备(slave device,通常是一个伪终端会话)进行通信。

函数的参数 oflag 是一个位掩码,用于指定打开文件的模式和权限,类似于 os.open() 函数中的标志。例如,你可以使用 os.O_RDWR 来打开一个可读写的文件,或者使用 os.O_NONBLOCK 来打开一个非阻塞的文件。

os.posix_openpt() 返回一个文件描述符,你可以使用这个描述符来访问新打开的伪终端的主设备。通常,你还需要使用 os.grantpt() 和 os.unlockpt() 函数来设置从设备的权限和解锁从设备的路径名,以便之后可以使用 os.ptsname() 来获取从设备的路径名。

下面是一个使用 os.posix_openpt(), os.grantpt(), os.unlockpt(), 和 os.ptsname() 的示例:

python 复制代码
import os
import pty

# 打开一个新的伪终端的主设备
master_fd = os.posix_openpt(os.O_RDWR | os.O_NOCTTY)

# 获取从设备的路径名
slave_name = os.ptsname(master_fd)

# 设置从设备的权限,使得拥有该伪终端的进程组可以访问
os.grantpt(master_fd)

# 解锁从设备,使得它可以被打开和使用
os.unlockpt(master_fd)

# 此时,你可以使用 master_fd 和 slave_name 来与伪终端从设备进行通信
# 例如,你可以通过 master_fd 向从设备写入数据,或者从从设备读取数据

# 关闭主设备文件描述符
os.close(master_fd)

请注意,伪终端的使用通常涉及比较底层的编程,并且可能需要了解终端 I/O、信号处理等相关知识。在 Python 中,有更高级别的库(如 pty 模块)提供了对伪终端操作的封装,使得使用更加简单。

此外,需要注意的是,os.posix_openpt() 在某些非 POSIX 系统上可能不可用。在不支持该函数的平台上,你可能需要寻找其他方法来创建和使用伪终端。

os.preadv(fd, buffers, offset, flags=0, /)

os.preadv() 是 Python 的一个系统调用接口,它允许从文件描述符 fd 中读取数据,并将数据直接存储在一个由 buffers 参数指定的缓冲区列表中。这个调用类似于 os.readv(),但 os.preadv() 不会在读取后更新文件描述符的文件位置,而是始终从指定的 offset 偏移量开始读取。

参数说明:

  • fd: 文件描述符,通常是通过 os.open() 或其他系统调用获得的。
  • buffers: 一个缓冲区对象的列表,数据会被直接读入这些缓冲区。每个缓冲区通常是一个字节串(bytes)或者可写的字节类型(如 bytearray)。
  • offset: 从文件的哪个位置开始读取。这是一个绝对位置,而不是相对于当前文件位置的偏移量。
  • flags: 一个可选的标志位,用于修改读取行为。通常设置为 0。

返回值是一个元组,包含两个元素:

  • 一个整数,表示实际读取的字节总数。
  • 一个列表,包含与 buffers 参数中相同数量的元素,每个元素表示对应缓冲区中实际填充的字节数。

os.preadv() 通常用于需要高效读取大量数据到多个缓冲区的场景,特别是在处理网络或文件 I/O 时。它允许应用程序减少不必要的内存拷贝,因为数据可以直接从内核空间读入用户空间的缓冲区。

下面是一个使用 os.preadv() 的简单示例:

python 复制代码
import os

# 打开一个文件
fd = os.open('example.txt', os.O_RDONLY)

# 创建两个缓冲区来存储读取的数据
buffer1 = bytearray(10)
buffer2 = bytearray(10)
buffers = [buffer1, buffer2]

# 从文件的第20个字节开始读取20个字节到缓冲区
n, read_counts = os.preadv(fd, buffers, 20)

# 处理读取到的数据
print("Read {} bytes:".format(n))
print("Buffer 1: {}, read {} bytes".format(buffer1, read_counts[0]))
print("Buffer 2: {}, read {} bytes".format(buffer2, read_counts[1]))

# 关闭文件描述符
os.close(fd)

在这个例子中,os.preadv() 从 example.txt 文件的第20个字节开始读取了20个字节的数据,并将这些数据直接存储在了 buffer1 和 buffer2 中。n 变量表示实际读取的字节总数,而 read_counts 列表表示每个缓冲区中实际填充的字节数。

请注意,os.preadv() 在非 POSIX 系统上可能不可用,或者可能需要使用不同的方法来达到相同的效果。在使用这些低级系统调用时,还需要注意错误处理和异常安全。

os.ptsname(fd, /)

os.ptsname(fd) 是 Python 的一个系统调用接口,用于获取与给定文件描述符 fd 关联的伪终端(pseudo-terminal,pty)从设备的路径名。通常,这个文件描述符是通过 os.posix_openpt() 或其他相关系统调用打开的伪终端主设备的文件描述符。

参数 fd 是一个已经打开的文件描述符,它必须指向一个有效的伪终端主设备。

os.ptsname() 返回一个字符串,表示与给定文件描述符关联的伪终端从设备的路径名。这个路径名通常是 /dev/pts/X 的形式,其中 X 是一个数字,表示从设备的唯一标识符。

下面是一个使用 os.posix_openpt(), os.grantpt(), os.unlockpt(), 和 os.ptsname() 的完整示例,用于打开一个新的伪终端并获取从设备的路径名:

python 复制代码
import os

# 打开一个新的伪终端的主设备
master_fd = os.posix_openpt(os.O_RDWR)

# 解锁从设备
os.unlockpt(master_fd)

# 获取从设备的路径名
slave_name = os.ptsname(master_fd)
print("Slave device name:", slave_name)

# 设置从设备的权限,使得拥有该伪终端的进程组可以访问
os.grantpt(master_fd)

# 在这里,你可以使用 master_fd 和 slave_name 来与伪终端从设备通信
# 例如,你可以通过 master_fd 向从设备写入数据,或者从从设备读取数据

# 关闭主设备文件描述符
os.close(master_fd)

请注意,os.ptsname() 仅适用于伪终端的文件描述符。如果你尝试对非伪终端的文件描述符调用此函数,它可能会引发一个错误。此外,这个函数可能不适用于非 POSIX 系统。

使用伪终端通常涉及到底层的终端 I/O 和信号处理,所以除非你确实需要这种级别的控制,否则通常建议使用更高级的库和接口,如 Python 的 pty 模块,来处理伪终端相关的操作。

os.pwrite(fd, str, offset, /)

os.pwrite() 是 Python 的一个系统调用接口,用于将数据写入到文件描述符 fd 指向的文件或设备中。与 os.write() 不同,os.pwrite() 允许你指定一个 offset 参数,该参数表示从文件的哪个位置开始写入数据。这样,你可以精确地控制数据应该写入文件的哪个部分。

参数说明:

  • fd: 文件描述符,通常是通过 os.open() 或其他系统调用获得的。
  • str: 要写入的数据,通常是一个字节串(bytes)。
  • offset: 从文件的哪个位置开始写入数据。这是一个绝对位置,而不是相对于当前文件位置的偏移量。

os.pwrite() 返回一个整数,表示实际写入的字节数。

请注意,os.pwrite() 通常用于那些需要精确控制写入位置的场景,比如对设备文件或某些特殊文件的操作。对于普通文件,通常使用 os.write() 或 os.lseek() 和 os.write() 的组合来写入数据。

下面是一个使用 os.pwrite() 的简单示例:

python 复制代码
import os

# 打开一个文件,准备写入数据
fd = os.open('example.txt', os.O_WRONLY | os.O_CREAT)

# 要写入的数据
data = b'Hello, World!'

# 从文件的第10个字节位置开始写入数据
n = os.pwrite(fd, data, 10)

# 确认写入的字节数
print(f"Wrote {n} bytes to the file.")

# 关闭文件描述符
os.close(fd)

在这个例子中,os.pwrite() 将字节串 data 从 example.txt 文件的第10个字节位置开始写入。如果文件原本小于10个字节,那么文件会被扩展以容纳新写入的数据。

需要注意的是,os.pwrite() 是针对底层文件描述符的操作,因此在使用时需要确保你对文件或设备的操作有正确的理解,并且正确处理可能出现的错误和异常。此外,不是所有的文件类型都支持使用 offset 参数进行写操作,这取决于文件系统的实现和文件的类型。

os.pwritev(fd, buffers, offset, flags=0, /)

os.pwritev() 是 Python 的一个系统调用接口,用于将数据从多个缓冲区写入到文件描述符 fd 指向的文件或设备中。与 os.writev() 类似,os.pwritev() 允许应用程序将数据直接从一个缓冲区列表中写入,而不是分多次调用 os.write()。不过,os.pwritev() 还允许你指定一个 offset 参数,以从文件的特定位置开始写入数据。

参数说明:

  • fd: 文件描述符,通常是通过 os.open() 或其他系统调用获得的。
  • buffers: 一个缓冲区对象的列表,数据会从这些缓冲区中读取并写入文件。每个缓冲区通常是一个字节串(bytes)或者可读的字节类型(如 bytearray)。
  • offset: 从文件的哪个位置开始写入数据。这是一个绝对位置,而不是相对于当前文件位置的偏移量。
  • flags: 一个可选的标志位,用于修改写入行为。通常设置为 0。

os.pwritev() 返回一个整数,表示实际写入的字节总数。

与 os.pwrite() 一样,os.pwritev() 通常用于需要精确控制写入位置的场景,比如对设备文件或某些特殊文件的操作。使用 os.pwritev() 可以减少系统调用的次数,从而提高数据写入的效率。

下面是一个使用 os.pwritev() 的简单示例:

python 复制代码
import os

# 打开一个文件,准备写入数据
fd = os.open('example.txt', os.O_WRONLY | os.O_CREAT)

# 创建两个缓冲区,包含要写入的数据
buffer1 = b'Hello'
buffer2 = b'World'
buffers = [buffer1, buffer2]

# 从文件的第10个字节位置开始写入数据
n = os.pwritev(fd, buffers, 10)

# 确认写入的字节数
print(f"Wrote {n} bytes to the file.")

# 关闭文件描述符
os.close(fd)

在这个例子中,os.pwritev() 将 buffer1 和 buffer2 中的数据从 example.txt 文件的第10个字节位置开始写入。如果文件原本小于10个字节,那么文件会被扩展以容纳新写入的数据。

请注意,os.pwritev() 和 os.pwrite() 一样,是针对底层文件描述符的操作,因此在使用时需要确保你对文件或设备的操作有正确的理解,并且正确处理可能出现的错误和异常。此外,不是所有的文件类型都支持使用 offset 参数进行写操作,这取决于文件系统的实现和文件的类型。

相关推荐
Shockang2 分钟前
LangGraph 状态机实战
人工智能
DLYSB_7 分钟前
存储运维实战:基于 Ceph Event 监听与 Python 适配器的分布式存储健康度物理声光响应架构
运维·ceph·python·报警灯
刹那芳华199214 分钟前
循环神经网络的从零开始实现(RNN)
人工智能·rnn·深度学习
阿童木写作24 分钟前
跨境图片翻译工具多合一,批量图片视频字幕翻译加智能抠图
人工智能·python·音视频·语音识别
科技之门24 分钟前
AI3D从建模到贴图、绑骨和动画的完整流程怎么做?V2Fun完整工作流指南
人工智能·3d·贴图
宇宙第一小趴菜25 分钟前
二、机器学习的应用领域和发展史
人工智能·机器学习
前端开发江鸟31 分钟前
我写过 MCP Server,却一直以为 MCP 只有 Tool
人工智能
天国梦1 小时前
自习室智能化升级避坑指南:天学网AI智习室方案实测与选型建议
大数据·人工智能
隐积1 小时前
3.1.7.Qt容器大家族(3):QVariant——万能盒子
开发语言·qt
阿里云云原生1 小时前
可用性从 99.9% 跃升至 99.995%:畅捷通如何用 AI 重塑运维底座?
运维·网络·人工智能