tempfile — 生成临时文件和目录

源代码: Lib/tempfile.py


此模块创建临时文件和目录。它适用于所有受支持的平台。TemporaryFileNamedTemporaryFileTemporaryDirectorySpooledTemporaryFile 是高级接口,提供自动清理并可用作上下文管理器mkstemp()mkdtemp() 是需要手动清理的低级函数。

所有用户可调用的函数和构造函数都接受额外的参数,允许直接控制临时文件和目录的位置和名称。此模块使用的文件名包含一串随机字符,这些文件可以在共享临时目录中安全创建。为了保持向后兼容性,参数顺序有些奇怪;建议使用关键字参数以提高清晰度。

该模块定义了以下用户可调用项

tempfile.TemporaryFile(mode='w+b', buffering=-1, encoding=None, newline=None, suffix=None, prefix=None, dir=None, *, errors=None)

返回一个可作为临时存储区域的类文件对象。该文件是使用与 mkstemp() 相同的规则安全创建的。它一关闭(包括对象被垃圾回收时进行的隐式关闭)就会被销毁。在 Unix 下,该文件的目录条目要么根本不创建,要么在文件创建后立即删除。其他平台不支持此功能;您的代码不应依赖于使用此函数创建的临时文件在文件系统中是否具有可见名称。

生成的对象可以用作上下文管理器(参见示例)。上下文完成后或文件对象销毁时,临时文件将从文件系统中删除。

mode 参数默认为 'w+b',以便创建的文件可以在不关闭的情况下进行读写。使用二进制模式是为了使其在所有平台上行为一致,而无论存储的数据如何。bufferingencodingerrorsnewline 的解释与 open() 相同。

dirprefixsuffix 参数的含义和默认值与 mkstemp() 相同。

在 POSIX 平台上,返回的对象是真正的文件对象。在其他平台上,它是一个类文件对象,其 file 属性是底层的真实文件对象。

如果 os.O_TMPFILE 标志可用且有效(Linux 特有,需要 Linux 内核 3.11 或更高版本),则使用它。

在既不是 Posix 也不是 Cygwin 的平台上,TemporaryFile 是 NamedTemporaryFile 的别名。

引发带有参数 fullpath审计事件 tempfile.mkstemp

3.5 版本中有所改变: 如果可用,现在使用 os.O_TMPFILE 标志。

3.8 版本中有所改变: 添加了 errors 参数。

tempfile.NamedTemporaryFile(mode='w+b', buffering=-1, encoding=None, newline=None, suffix=None, prefix=None, dir=None, delete=True, *, errors=None, delete_on_close=True)

此函数的运行方式与 TemporaryFile() 完全相同,但有以下区别

  • 此函数返回的文件保证在文件系统中具有可见名称。

  • 为了管理命名文件,它扩展了 TemporaryFile() 的参数,增加了 deletedelete_on_close 参数,它们决定了命名文件是否以及如何自动删除。

返回的对象始终是一个类文件对象,其 file 属性是底层真实文件对象。这个类文件对象可以在 with 语句中使用,就像普通文件一样。临时文件的名称可以从返回的类文件对象的 name 属性中检索。在 Unix 上,与 TemporaryFile() 不同,目录条目在文件创建后不会立即取消链接。

如果 delete 为 True(默认)且 delete_on_close 为 True(默认),则文件在关闭后立即删除。如果 delete 为 True 且 delete_on_close 为 False,则文件仅在上下文管理器退出时删除,或者在类文件对象被终结时删除。在这种情况下,删除并不总是保证的(参见 object.__del__())。如果 delete 为 False,则 delete_on_close 的值将被忽略。

因此,要使用临时文件的名称在关闭文件后重新打开文件,要么确保在关闭时不要删除文件(将 delete 参数设置为 False),要么,如果临时文件是在 with 语句中创建的,则将 delete_on_close 参数设置为 False。推荐后一种方法,因为它有助于在上下文管理器退出时自动清理临时文件。

在临时文件仍然打开时通过其名称再次打开文件的工作方式如下

  • 在 POSIX 上,文件始终可以再次打开。

  • 在 Windows 上,请确保至少满足以下条件之一

    • delete 为 False

    • 额外的打开共享删除访问权限(例如,通过使用标志 O_TEMPORARY 调用 os.open()

    • delete 为 True 但 delete_on_close 为 False。请注意,在这种情况下,不共享删除访问权限的额外打开(例如,通过内置 open() 创建的)必须在退出上下文管理器之前关闭,否则在上下文管理器退出时调用 os.unlink() 将因 PermissionError 而失败。

在 Windows 上,如果 delete_on_close 为 False,并且文件是在用户缺乏删除访问权限的目录中创建的,则在上下文管理器退出时调用 os.unlink() 将因 PermissionError 而失败。当 delete_on_close 为 True 时不会发生这种情况,因为打开时会请求删除访问权限,如果未授予请求的访问权限,则会立即失败。

在 POSIX(仅限)上,被 SIGKILL 突然终止的进程无法自动删除其创建的任何 NamedTemporaryFiles。

引发带有参数 fullpath审计事件 tempfile.mkstemp

3.8 版本中有所改变: 添加了 errors 参数。

3.12 版本中有所改变: 添加了 delete_on_close 参数。

class tempfile.SpooledTemporaryFile(max_size=0, mode='w+b', buffering=-1, encoding=None, newline=None, suffix=None, prefix=None, dir=None, *, errors=None)

此类的操作与 TemporaryFile() 完全相同,只是数据在内存中缓冲,直到文件大小超过 max_size,或者直到调用文件的 fileno() 方法,此时内容被写入磁盘,操作按照 TemporaryFile() 的方式进行。

rollover()

生成的文件有一个额外的 rollover() 方法,它使文件无论大小如何都滚动到磁盘文件。

返回的对象是一个类文件对象,其 _file 属性要么是 io.BytesIOio.TextIOWrapper 对象(取决于指定的是二进制 mode 还是文本 mode),要么是真正的文件对象,具体取决于是否已调用 rollover()。此文件类对象可以在 with 语句中使用,就像普通文件一样。

3.3 版本中有所改变: truncate 方法现在接受 size 参数。

3.8 版本中有所改变: 添加了 errors 参数。

3.11 版本中有所改变: 完全实现了 io.BufferedIOBaseio.TextIOBase 抽象基类(取决于指定的是二进制 mode 还是文本 mode)。

class tempfile.TemporaryDirectory(suffix=None, prefix=None, dir=None, ignore_cleanup_errors=False, *, delete=True)

此类别以与 mkdtemp() 相同的规则安全地创建临时目录。生成的对象可以用作上下文管理器(参见示例)。上下文完成后或临时目录对象销毁时,新创建的临时目录及其所有内容将从文件系统中删除。

name

目录名称可以从返回对象的 name 属性中检索。当返回对象用作上下文管理器时,如果存在 with 语句中的 as 子句的目标,则 name 将分配给它。

cleanup()

可以通过调用 cleanup() 方法显式清理目录。如果 ignore_cleanup_errors 为 True,则在显式或隐式清理期间发生的任何未处理的异常(例如在 Windows 上删除打开的文件时出现 PermissionError)都将被忽略,剩余的可删除项将“尽力”删除。否则,错误将在清理发生的任何上下文中引发(cleanup() 调用、退出上下文管理器、对象被垃圾回收或解释器关闭期间)。

delete 参数可用于在退出上下文时禁用目录树的清理。虽然上下文管理器禁用退出上下文时采取的操作可能看起来不寻常,但在调试期间或当您需要根据其他逻辑有条件地进行清理行为时,它可能很有用。

引发带有参数 fullpath审计事件 tempfile.mkdtemp

在 3.2 版本加入。

3.10 版本中有所改变: 添加了 ignore_cleanup_errors 参数。

3.12 版本中有所改变: 添加了 delete 参数。

tempfile.mkstemp(suffix=None, prefix=None, dir=None, text=False)

以尽可能最安全的方式创建临时文件。假设平台正确实现了 os.O_EXCL 标志用于 os.open(),则在文件创建中没有竞争条件。文件仅由创建用户 ID 可读写。如果平台使用权限位来指示文件是否可执行,则该文件对任何人均不可执行。文件描述符不被子进程继承。

TemporaryFile() 不同,mkstemp() 的用户负责在完成临时文件后删除它。

如果 suffix 不为 None,则文件名将以该后缀结尾,否则没有后缀。mkstemp() 不在文件名和后缀之间加点;如果需要,请将其放在 suffix 的开头。

如果 prefix 不为 None,则文件名将以该前缀开头;否则,使用默认前缀。默认值是 gettempprefix()gettempprefixb() 的返回值,视情况而定。

如果 dir 不为 None,则文件将在该目录中创建;否则,使用默认目录。默认目录从平台相关的列表中选择,但应用程序用户可以通过设置 TMPDIRTEMPTMP 环境变量来控制目录位置。因此,无法保证生成的 文件名具有任何好的特性,例如通过 os.popen() 传递给外部命令时不需要引用。

如果 suffixprefixdir 中的任何一个不为 None,它们必须是相同类型。如果它们是字节串,则返回的名称将是字节串而不是字符串。如果您想强制返回字节串值而其他行为保持默认,请传入 suffix=b''

如果指定了 text 且为 True,则文件以文本模式打开。否则(默认),文件以二进制模式打开。

mkstemp() 返回一个元组,其中包含一个打开文件的 OS 级别句柄(与 os.open() 返回的相同)和该文件的绝对路径名,按此顺序。

引发带有参数 fullpath审计事件 tempfile.mkstemp

3.5 版本中有所改变: 现在可以以字节串形式提供 suffixprefixdir,以获取字节串返回值。在此之前,只允许使用字符串。suffixprefix 现在接受并默认为 None,以使用适当的默认值。

3.6 版本中有所改变: dir 参数现在接受路径类对象

tempfile.mkdtemp(suffix=None, prefix=None, dir=None)

以尽可能最安全的方式创建临时目录。在目录的创建中没有竞争条件。目录仅由创建用户 ID 可读、可写和可搜索。

mkdtemp() 的用户负责在完成临时目录及其内容后删除它们。

prefixsuffixdir 参数与 mkstemp() 的相同。

mkdtemp() 返回新目录的绝对路径名。

引发带有参数 fullpath审计事件 tempfile.mkdtemp

3.5 版本中有所改变: 现在可以以字节串形式提供 suffixprefixdir,以获取字节串返回值。在此之前,只允许使用字符串。suffixprefix 现在接受并默认为 None,以使用适当的默认值。

3.6 版本中有所改变: dir 参数现在接受路径类对象

3.12 版本中有所改变: 即使 dir 是相对路径,mkdtemp() 现在也始终返回绝对路径。

tempfile.gettempdir()

返回用于临时文件的目录名称。这定义了此模块中所有函数的 dir 参数的默认值。

Python 搜索一个标准目录列表,以找到一个调用用户可以在其中创建文件的目录。该列表是

  1. TMPDIR 环境变量指定的目录。

  2. TEMP 环境变量指定的目录。

  3. TMP 环境变量指定的目录。

  4. 平台特定的位置

    • 在 Windows 上,目录 C:\TEMPC:\TMP\TEMP\TMP,按此顺序。

    • 在所有其他平台上,目录 /tmp/var/tmp/usr/tmp,按此顺序。

  5. 作为最后的手段,当前工作目录。

此搜索的结果已缓存,请参阅下面 tempdir 的描述。

3.10 版本中有所改变: 始终返回一个 str。此前,它会返回任何 tempdir 值,无论类型如何,只要它不是 None

tempfile.gettempdirb()

gettempdir() 相同,但返回值为字节串。

在 3.5 版本加入。

tempfile.gettempprefix()

返回用于创建临时文件的文件名前缀。这不包含目录组件。

tempfile.gettempprefixb()

gettempprefix() 相同,但返回值为字节串。

在 3.5 版本加入。

该模块使用一个全局变量来存储由 gettempdir() 返回的用于临时文件的目录名称。可以直接设置它来覆盖选择过程,但不建议这样做。此模块中的所有函数都接受一个 dir 参数,可用于指定目录。这是推荐的方法,不会因更改全局 API 行为而让其他不知情的代码感到意外。

tempfile.tempdir

当设置为非 None 的值时,此变量定义此模块中定义函数的 dir 参数的默认值,包括其类型,字节串或字符串。它不能是路径类对象

如果在调用上述函数中的任何一个(gettempprefix() 除外)时 tempdirNone(默认),则它会根据 gettempdir() 中描述的算法进行初始化。

备注

请注意,如果您将 tempdir 设置为字节值,则会产生一个糟糕的副作用:当未提供显式类型为 str 的 prefixsuffixdir 参数时,mkstemp()mkdtemp() 的全局默认返回类型会更改为字节串。请不要编写期望或依赖此行为的代码。这种尴尬的行为是为了与历史实现兼容而保留的。

示例

以下是 tempfile 模块典型用法的一些示例

>>> import tempfile

# create a temporary file and write some data to it
>>> fp = tempfile.TemporaryFile()
>>> fp.write(b'Hello world!')
# read data from file
>>> fp.seek(0)
>>> fp.read()
b'Hello world!'
# close the file, it will be removed
>>> fp.close()

# create a temporary file using a context manager
>>> with tempfile.TemporaryFile() as fp:
...     fp.write(b'Hello world!')
...     fp.seek(0)
...     fp.read()
b'Hello world!'
>>>
# file is now closed and removed

# create a temporary file using a context manager
# close the file, use the name to open the file again
>>> with tempfile.NamedTemporaryFile(delete_on_close=False) as fp:
...     fp.write(b'Hello world!')
...     fp.close()
... # the file is closed, but not removed
... # open the file again by using its name
...     with open(fp.name, mode='rb') as f:
...         f.read()
b'Hello world!'
>>>
# file is now removed

# create a temporary directory using the context manager
>>> with tempfile.TemporaryDirectory() as tmpdirname:
...     print('created temporary directory', tmpdirname)
>>>
# directory and contents have been removed

已弃用的函数和变量

创建临时文件的一种历史方法是首先使用 mktemp() 函数生成文件名,然后使用此名称创建文件。不幸的是,这不安全,因为在调用 mktemp() 和第一个进程随后尝试创建文件之间,另一个进程可能会使用此名称创建文件。解决方案是将这两个步骤结合起来并立即创建文件。这种方法被 mkstemp() 和上述其他函数使用。

tempfile.mktemp(suffix='', prefix='tmp', dir=None)

自 2.3 版本弃用: 请改用 mkstemp()

返回在调用时不存在的文件的绝对路径名。prefixsuffixdir 参数与 mkstemp() 的参数类似,只是不支持字节文件名、suffix=Noneprefix=None

警告

使用此函数可能会在您的程序中引入安全漏洞。当您开始处理它返回的文件名时,其他人可能已经抢先一步。mktemp() 的用法可以很容易地替换为 NamedTemporaryFile(),并传入 delete=False 参数

>>> f = NamedTemporaryFile(delete=False)
>>> f.name
'/tmp/tmptjujjt'
>>> f.write(b"Hello World!\n")
13
>>> f.close()
>>> os.unlink(f.name)
>>> os.path.exists(f.name)
False