ZetCode

Python os.close 函数

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

本综合指南探讨了 Python 的 os.close 函数,该函数用于关闭文件描述符。我们将介绍正确的资源管理、错误处理和实际的文件操作示例。

基本定义

os.close 函数关闭文件描述符,使其可供重用。 这是一个释放系统资源的底层操作。

关键参数:fd(要关闭的文件描述符)。 如果描述符无效,则引发 OSError。 成功时返回 None。

基本文件描述符关闭

此示例演示了如何打开文件并使用 os.close 正确关闭其描述符。 始终关闭描述符以避免泄漏。

basic_close.py
import os

# Open a file and get its descriptor
fd = os.open("example.txt", os.O_RDWR | os.O_CREAT)

try:
    # Work with the file descriptor
    os.write(fd, b"Hello World")
finally:
    # Ensure descriptor is closed
    os.close(fd)
    print("File descriptor closed")

# Verify descriptor is closed
try:
    os.write(fd, b"More data")
except OSError as e:
    print(f"Error: {e}")

该示例展示了使用 try/finally 的正确资源管理。 finally 块确保即使发生错误,描述符也会被关闭。

尝试使用已关闭的描述符会引发 OSError。 这证实了描述符已正确关闭。

关闭多个描述符

使用多个文件时,必须单独关闭每个描述符。 此示例显示了多个资源的正确处理。

multiple_close.py
import os

# Open multiple files
fd1 = os.open("file1.txt", os.O_RDWR | os.O_CREAT)
fd2 = os.open("file2.txt", os.O_RDWR | os.O_CREAT)
fd3 = os.open("file3.txt", os.O_RDWR | os.O_CREAT)

try:
    # Work with files
    os.write(fd1, b"Data for file1")
    os.write(fd2, b"Data for file2")
    os.write(fd3, b"Data for file3")
finally:
    # Close all descriptors
    for fd in [fd1, fd2, fd3]:
        try:
            os.close(fd)
            print(f"Closed descriptor {fd}")
        except OSError as e:
            print(f"Error closing {fd}: {e}")

即使某些操作失败,此模式也能确保所有描述符都正确关闭。 每个关闭都包含在它自己的 try/except 中。

该循环有效地处理关闭多个描述符,同时维护每个操作的错误处理。

上下文管理器替代方案

Python 的上下文管理器提供了一种更简洁的替代手动 os.close 调用的方法。 此示例比较了这两种方法。

context_manager.py
import os
from contextlib import contextmanager

# Manual approach
fd = os.open("manual.txt", os.O_RDWR | os.O_CREAT)
try:
    os.write(fd, b"Manual management")
finally:
    os.close(fd)

# Context manager approach
@contextmanager
def open_fd(path, flags):
    fd = os.open(path, flags)
    try:
        yield fd
    finally:
        os.close(fd)

with open_fd("context.txt", os.O_RDWR | os.O_CREAT) as fd:
    os.write(fd, b"Context manager")

# Built-in open() is preferred for regular files
with open("regular.txt", "w") as f:
    f.write("High-level interface")

上下文管理器方法封装了打开/关闭模式,使代码更简洁且不易出错。

对于大多数文件操作,首选 Python 内置的 open() 而不是底层描述符管理。

错误处理

os.close 可能会为无效的描述符引发 OSError。 此示例演示了正确的错误处理模式。

error_handling.py
import os

def safe_close(fd):
    """Safely close a file descriptor with error handling."""
    try:
        os.close(fd)
        print(f"Successfully closed descriptor {fd}")
    except OSError as e:
        print(f"Error closing descriptor {fd}: {e}")

# Valid descriptor
fd1 = os.open("valid.txt", os.O_RDWR | os.O_CREAT)
safe_close(fd1)

# Already closed descriptor
safe_close(fd1)

# Invalid descriptor
safe_close(9999)

# Double close protection
fd2 = os.open("another.txt", os.O_RDWR | os.O_CREAT)
safe_close(fd2)
fd2 = None  # Prevent accidental reuse

safe_close 函数为描述符关闭操作提供强大的错误处理。

关闭后将描述符设置为 None 有助于防止意外重用已关闭的描述符。

管道通信

使用管道时,os.close 至关重要。 此示例显示了进程间通信中正确的管道清理。

pipe_example.py
import os

# Create a pipe
r, w = os.pipe()

pid = os.fork()

if pid == 0:
    # Child process
    os.close(r)  # Close unused read end
    os.write(w, b"Hello from child")
    os.close(w)
    os._exit(0)
else:
    # Parent process
    os.close(w)  # Close unused write end
    data = os.read(r, 100)
    os.close(r)
    print(f"Received: {data.decode()}")
    os.waitpid(pid, 0)

管道需要在两个进程中关闭未使用的端点,以防止挂起和资源泄漏。

该示例显示了父进程和子进程中正确的清理,以实现正确的管道操作。

文件描述符继承

此示例演示了文件描述符在进程边界上的行为以及正确关闭的重要性。

inheritance_example.py
import os

# Open file in parent
fd = os.open("inherited.txt", os.O_RDWR | os.O_CREAT)
os.write(fd, b"Parent data")

pid = os.fork()

if pid == 0:
    # Child process
    print(f"Child can access descriptor {fd}")
    os.lseek(fd, 0, os.SEEK_SET)
    data = os.read(fd, 100)
    print(f"Child read: {data.decode()}")
    
    # Close in child (doesn't affect parent)
    os.close(fd)
    os._exit(0)
else:
    # Parent process
    os.waitpid(pid, 0)
    print("Child process finished")
    
    # Parent can still use descriptor
    os.write(fd, b"\nMore parent data")
    os.close(fd)  # Final close

文件描述符由子进程继承。 每个进程都必须独立关闭它们。

在子进程中关闭不会影响父进程的描述符副本。 两者都应关闭其副本。

安全注意事项

最佳实践

资料来源

作者

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

列出所有 Python 教程