ZetCode

Python os.write 函数

上次修改时间:2025 年 4 月 11 日

本综合指南探讨 Python 的 os.write 函数,该函数使用文件描述符执行底层文件写入。我们将介绍文件描述符、字节字符串、返回值和实际示例。

基本定义

os.write 函数将字节写入文件描述符。 它是一种绕过 Python 文件对象层的底层操作。

主要参数:fd(文件描述符),data(类字节对象)。 返回实际写入的字节数。 需要正确的文件打开和权限。

基本文件写入

此示例演示了使用 os.write 将数据写入文件的最简单方法。 我们首先打开文件以获取文件描述符。

basic_write.py
import os

# Open file and get file descriptor
fd = os.open("output.txt", os.O_WRONLY | os.O_CREAT)

# Write bytes to file
data = b"Hello, World!\n"
bytes_written = os.write(fd, data)
print(f"Wrote {bytes_written} bytes")

# Close file descriptor
os.close(fd)

该代码以只写访问模式打开文件,如果需要则创建文件,写入字节,然后关闭描述符。 注意字节字面量的前缀 'b'。

始终关闭文件描述符以防止资源泄漏。 返回值显示实际写入了多少字节。

写入多个块

可以多次调用 os.write 以分块写入数据。 此示例显示了对同一文件描述符的顺序写入。

chunked_write.py
import os

fd = os.open("log.txt", os.O_WRONLY | os.O_CREAT | os.O_APPEND)

messages = [
    b"System started\n",
    b"Loading modules...\n",
    b"Initialization complete\n"
]

for msg in messages:
    bytes_written = os.write(fd, msg)
    print(f"Wrote {bytes_written} bytes")

os.close(fd)

我们以追加模式打开文件以保留现有内容。 每个字符串都是单独写入的,并在每次写入后报告进度。

O_APPEND 标志确保写入操作转到文件末尾,即使其他进程同时写入该文件也是如此。

处理大型文件

对于大型文件,以固定大小的块写入数据是高效的。 此示例演示了以较小的片段写入大型字节数组。

large_file_write.py
import os

# Generate 1MB of data
data = b"X" * (1024 * 1024)

fd = os.open("large_file.bin", os.O_WRONLY | os.O_CREAT)

chunk_size = 4096  # 4KB chunks
total_written = 0

for i in range(0, len(data), chunk_size):
    chunk = data[i:i + chunk_size]
    written = os.write(fd, chunk)
    total_written += written
    print(f"Written {total_written} bytes", end="\r")

os.close(fd)
print(f"\nTotal written: {total_written} bytes")

该代码以 4KB 的块写入 1MB 的文件。 这种方法节省内存,并在操作期间提供进度反馈。

注意 print 中的回车符 (\r) 以更新同一行,从而创建进度指示器效果。

错误处理

os.write 可能会引发异常。 此示例显示了针对常见场景(如磁盘已满或权限问题)的正确错误处理。

error_handling.py
import os
import errno

try:
    fd = os.open("protected.txt", os.O_WRONLY | os.O_CREAT)
    data = b"Attempting to write to protected file\n"
    
    try:
        bytes_written = os.write(fd, data)
        print(f"Successfully wrote {bytes_written} bytes")
    except OSError as e:
        if e.errno == errno.ENOSPC:
            print("Error: No space left on device")
        elif e.errno == errno.EBADF:
            print("Error: Bad file descriptor")
        else:
            print(f"Write error: {e}")
    finally:
        os.close(fd)
except PermissionError:
    print("Error: Permission denied for file creation")
except OSError as e:
    print(f"File open error: {e}")

该示例演示了嵌套的 try-except 块,以处理文件打开和写入阶段的不同错误场景。

特定的错误编号 (errno) 有助于识别确切的故障原因,以便进行适当的处理。

非阻塞 I/O

对于非阻塞文件描述符,os.write 可能会写入比请求的字节数更少的字节。 此示例显示了如何处理部分写入。

non_blocking.py
import os
import errno

# Create a named pipe (run this only once)
if not os.path.exists("mypipe"):
    os.mkfifo("mypipe")

# Open in non-blocking mode
fd = os.open("mypipe", os.O_WRONLY | os.O_NONBLOCK)

data = b"X" * 65536  # Large chunk of data
total = len(data)
written = 0

try:
    while written < total:
        try:
            n = os.write(fd, data[written:])
            if n == 0:
                print("Write would block")
                break
            written += n
            print(f"Written {written}/{total} bytes")
        except OSError as e:
            if e.errno == errno.EAGAIN:
                print("Resource temporarily unavailable")
                break
            raise
finally:
    os.close(fd)

该代码演示了以非阻塞模式写入命名管道。 它处理部分写入和管道已满时发生的 EAGAIN 错误。

非阻塞 I/O 对于在执行 I/O 操作时必须保持响应的应用程序非常有用。

二进制数据写入

os.write 是写入二进制数据的理想选择。 此示例显示了如何使用 struct 模块写入结构化的二进制数据。

binary_data.py
import os
import struct

fd = os.open("data.bin", os.O_WRONLY | os.O_CREAT)

# Pack different data types into bytes
points = [
    struct.pack("ffi", 1.5, 2.5, 10),  # x, y, color
    struct.pack("ffi", 3.1, 4.2, 20),
    struct.pack("ffi", 5.0, 6.0, 30)
]

for point in points:
    os.write(fd, point)

os.close(fd)
print("Binary data written successfully")

该示例以二进制格式写入三个点(每个点包含两个浮点数和一个整数)。 struct.pack 将 Python 值转换为字节。

二进制文件写入在性能敏感的应用程序(如游戏或科学计算)中很常见。

标准输出写入

文件描述符 1 表示标准输出。 此示例显示了使用 os.write 直接写入 stdout。

stdout_write.py
import os
import sys

# Method 1: Using file descriptor 1
os.write(1, b"Writing to stdout via file descriptor\n")

# Method 2: Using sys.stdout's fileno()
stdout_fd = sys.stdout.fileno()
os.write(stdout_fd, b"Writing via sys.stdout's descriptor\n")

# Method 3: Using os.fdopen
with os.fdopen(1, "wb") as f:
    f.write(b"Writing via fdopen wrapper\n")

该示例演示了三种写入 stdout 的方法。 第一种方法使用众所周知的描述符编号 (1),第二种方法使用 sys.stdout 的描述符。

当您需要绕过 Python 的缓冲或在较低级别工作时,直接 stdout 写入可能很有用。

安全注意事项

最佳实践

资料来源

作者

我叫 Jan Bodnar,是一位充满激情的程序员,拥有丰富的编程经验。 自 2007 年以来,我一直撰写编程文章。 迄今为止,我已撰写了超过 1,400 篇文章和 8 本电子书。 我拥有超过十年的编程教学经验。

列出所有 Python 教程