Watch at Ease看见世界,读懂生活。

科技 · 实用指南

NamedTemporaryFile 在 POSIX 正常、Windows 失败?先选重开与删除合同

临时路径有三位责任人:创建者、第二次打开者和清理者。把名称交出去前,先决定哪个句柄保持打开。

Original diagram showing creator, consumer, and cleanup as three owners of a named temporary file.
原创示意图:传递路径前绑定创建者、消费者和清理责任。 Watch at Ease

NamedTemporaryFile 提供可见路径,却不保证每个第二句柄都能重开、重命名或删除。POSIX 可在原句柄打开时再次打开;Windows 会核对所有现有句柄的访问与共享模式,因此 Linux 正常的流程可能在 Windows 抛出 PermissionError。

创建前先选生命周期合同:消费者得到已关闭路径、在创建者仍打开时重开,还是负责最终清理?随后把 delete 与 delete_on_close 绑定到这个选择,离开上下文前关闭不兼容句柄,并验证消费成功和最终删除。

创建前写明下一位所有者

Write down whether the next user is the same Python handle, a second Python open, a library that accepts a path, or an external process. Also state whether that 消费者 needs only read/write access or may rename, replace, or keep 文件 mapped.

If the 消费者 accepts a file object, prefer passing the existing object and avoid a second pathname open. If it requires a path, the handle and 清理 contract must be explicit.

选择三种生命周期合同之一

For same-context reopen on Python 3.12+, delete=True with delete_on_close=False keeps automatic context-exit 清理 while allowing an ordinary second open on Windows. Close that second handle before leaving the context.

For an external process or API that cannot share delete access, flush and close the producer, use delete=False, pass the path, wait for the 消费者, then remove 文件 in finally. For a specialized second Python open that shares delete access, use the documented O_TEMPORARY route only when every participant follows the same contract.

区分 flush、close 与进程结束

flush makes Python buffers visible but does not release the Windows handle or its share-mode record. close releases that handle. Waiting for the subprocess proves only that process exit occurred; it does not prove another library or mapped view released 文件.

Keep the producer, 消费者, and 清理 timestamps in a small ledger. A 清理 PermissionError is evidence of an outstanding handle or missing delete right, not a reason to silently leak the path.

把重命名和删除当成独立访问类别

Microsoft documents that delete access includes rename. A file can be readable and writable yet still reject os.replace, fileinput in-place editing, or 清理 because a prior handle did not share delete access.

Do not diagnose every WinError 32 as another process. Record the exact operation, every handle you own, whether each is closed, and whether the 消费者 might retain a mapping.

在两个平台验证合同

Create a fixture that writes bytes, reopens or hands off the path exactly as production does, confirms the 消费者 read the expected hash, closes every handle, exits the context, and asserts whether the path should exist. Run it on Windows and POSIX.

For delete=False, assert deletion in finally and fail loudly if removal fails. For delete_on_close=False, assert the second handle closes before context exit. Also test the exception path so 清理 is not dependent on a successful 消费者.

Original diagram comparing incompatible and compatible Windows file sharing contracts.
原创示意图:Windows 会按所有打开句柄及其共享模式核对访问。 Watch at Ease