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() 完全相同,但以下差异除外

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

  • 为了管理命名文件,它使用 deletedelete_on_close 参数扩展了 TemporaryFile() 的参数,这些参数确定是否以及如何自动删除命名文件。

返回的对象始终是一个类文件对象,其 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),要么是一个真正的文件对象,具体取决于是否已调用 rollover()。这个类文件对象可以像普通文件一样在 with 语句中使用。

3.3 版本更改: truncate 方法现在接受 size 参数。

在 3.8 版本中变更: 添加了 errors 参数。

3.11 版本更改: 完全实现了 io.BufferedIOBaseio.TextIOBase 抽象基类(取决于是否指定了二进制或文本 mode)。

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

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

name

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

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.open() 返回的)以及该文件的绝对路径名,顺序如此。

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

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

3.6 版本更改: dir 参数现在接受 path-like object

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

以尽可能安全的方式创建一个临时目录。在目录创建过程中不会出现竞争条件。该目录仅对创建用户 ID 可读、可写和可搜索。

mkdtemp() 的用户有责任在使用完临时目录及其内容后将其删除。

prefixsuffixdir 参数与 mkstemp() 的相同。

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

使用参数 fullpath 引发 审计事件 tempfile.mkdtemp

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

3.6 版本更改: dir 参数现在接受 path-like object

3.12 版本更改: mkdtemp() 现在始终返回绝对路径,即使 dir 是相对路径也是如此。

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 版本更改: 始终返回字符串。以前,它会返回任何 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 设置为字节值,则会产生一个不良的副作用:当没有提供类型为字符串的显式 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