这部分内容在底层开发、并发编程或者需要精细控制输入输出时非常重要。不过,它确实比直接用 open() 函数要稍微复杂一点,也容易踩坑。别担心,我们一起来看。

简单来说,当操作系统打开一个文件时,它会分配一个非负整数来标识这个打开的文件。这个整数就是文件描述符。

0
标准输入 (stdin)

1
标准输出 (stdout)

2
标准错误 (stderr)

其他文件则从 3 开始往后排。

用 os.open() 打开的文件不会像 with open(...) 那样自动关闭。如果你打开太多而不手动关闭,程序会抛出 OSError: [Errno 24] Too many open files。

open() 返回的是一个 File Object (带有 .read(), .write() 方法的对象)。

os.open() 返回的是一个 Integer (整数 ID)。 你不能直接在 os.open() 的结果上调用 .read(),必须配合 os.read(fd, length) 使用。

让我们对比一下“底层底层操作”和“推荐的 Python 风格操作”。

这种方式通常用于需要特定的文件权限(如 os.O_CREAT | os.O_WRONLY)或非阻塞模式时。

import os

# 定义文件名
path = "example.txt"

try:
    # os.O_RDWR: 读写模式, os.O_CREAT: 如果不存在则创建
    # 0o644 是文件权限 (Linux 风格)
    fd = os.open(path, os.O_RDWR | os.O_CREAT)
    
    # 写入内容(必须传入 bytes)
    text = "你好,这是底层操作!"
    os.write(fd, text.encode('utf-8'))
    
    # 将指针移回开头以读取
    os.lseek(fd, 0, os.SEEK_SET)
    
    # 读取内容
    content = os.read(fd, 100)
    print(f"读取到的内容: {content.decode('utf-8')}")

finally:
    # 重点:必须手动关闭!
    if 'fd' in locals():
        os.close(fd)
        print("文件描述符已关闭。")

除非你有非常特殊的需求(比如通过 os.dup2 重定向流),否则建议使用 io 模块或内置的 open() 配合 with 语句。

# 这种方法更安全,因为它会自动处理关闭逻辑,即使发生错误也不怕
path = "example.txt"

with open(path, "w+", encoding="utf-8") as f:
    f.write("这是更推荐的 Python 风格代码!")
    f.seek(0)
    print(f"读取内容: {f.read()}")

有时候你必须先拿底层 fd(比如从 socket 或管道获取),但又想用方便的 .read() 方法。你可以使用 os.fdopen()。

import os

# 假设我们有一个文件描述符 fd
fd = os.open("test.log", os.O_RDWR | os.O_CREAT)

# 将 fd 封装成高级的文件对象
with os.fdopen(fd, 'w+', encoding='utf-8') as f:
    f.write("通过 fdopen 写入的内容")
    # 注意:此时 with 语句结束会自动调用 os.close(fd)

能用 with open() 就用 with open()
它更安全、易读。

手动关闭
如果你确实用了 os.open(),请务必将其放在 try...finally 块中确保 os.close(fd) 被执行。

字节流
记得 os.write() 和 os.read() 处理的是 bytes,不是字符串,记得编码和解码。

Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐