tempfile.mkstemp 的 OS 级句柄有什么用?

What is the OS-level handle of tempfile.mkstemp good for?

当我需要在可能保留的目录中创建文件时,我使用 tempfile.mkstemp,但我不关心文件名。应该只是目前不存在的东西,有前缀-和后缀。

到目前为止我忽略的文档的一部分是

mkstemp() returns a tuple containing an OS-level handle to an open file (as would be returned by os.open()) and the absolute pathname of that file, in that order.

什么是OS级句柄,应该如何使用?

背景

我一直都是这样用的:

from tempfile import mstemp

_, path = mkstemp(prefix=prefix, suffix=suffix, dir=dir)

with open(path, "w") as f:
    f.write(data)

# do something

os.remove(path)

目前为止一切正常。然而,今天我写了一个小脚本,它生成巨大的文件并删除它们。脚本中止执行并显示消息

OSError: [Errno 28] No space left on device

我检查时,有 80 GB 的空闲空间。

我怀疑os.remove只有"marked"个要删除的文件,但文件没有被正确删除。下一个怀疑是我可能需要在 OS 实际释放该磁盘 space.

之前关闭 OS 级别的句柄

你的猜测是对的。 os.remove 仅删除包含文件名的目录条目。但是,文件数据保持完好并继续消耗磁盘上的 space,直到文件上最后一个打开的描述符被关闭。在此期间,通过现有描述符对文件的正常操作继续工作,这意味着您仍然可以使用 _ 描述符在 os.remove 返回后查找、读取或写入文件。

事实上,通常的做法是在继续使用描述符对文件内容进行操作之前立即 os.remove 文件。这可以防止文件被任何其他进程打开,也意味着如果该程序在到达稍后的 os.remove.

之前意外终止,文件将不会被保留。

当然,只有当您愿意并且能够对文件的所有操作使用低级描述符时,这才有效,如果您使用os.fdopen 方法在描述符之上构造一个文件对象,并将该新对象用于所有操作。显然你只想做其中一件事情;混合对同一基础文件的描述符访问和文件对象访问会产生意外结果。

os.fdopen(_) 应该比 open(path) 执行得更快,但它没有 open 具有的上下文管理器集成,因此它不能直接用于 with 构造.我认为您可以使用 contextlib.closing 来解决这个问题。