不用在 Python 中创建实际文件就可以生成临时文件名

在 Python 中生成随机文件名的最佳方法的答案显示了如何在 Python 中创建临时文件。

在我的案例中,我只需要一个临时文件名。
调用 tempfile.NamedTemporaryFile()会在实际创建文件之后返回一个文件句柄。

有没有办法只得到一个文件名? 我试过这样:

# Trying to get temp file path
tf = tempfile.NamedTemporaryFile()
temp_file_name = tf.name
tf.close()
# Here is my real purpose to get the temp_file_name
f = gzip.open(temp_file_name ,'wb')
...
76538 次浏览

如果您想要一个临时文件名,只能调用内部临时文件函数 _get_candidate_names():

import tempfile


temp_name = next(tempfile._get_candidate_names())
% e.g. px9cp65s

再次调用 next,将返回另一个名称等。这不会给出临时文件夹的路径。要获得默认的‘ tmp’目录,请使用:

defult_tmp_dir = tempfile._get_default_tempdir()
% results in: /tmp

正如 Joachim Isaksson 在评论中所说,如果你只是得到一个名字,如果其他程序在你的程序之前使用这个名字,你可能会遇到问题。机会很渺茫,但并非不可能。

因此,在这种情况下,安全的做法是使用完整的 GzipFile()构造函数,它具有签名

GzipFile( [filename[, mode[, compresslevel[, fileobj]]]])

因此,您可以将打开的 fileobj 和文件名(如果愿意)传递给它。有关详细信息,请参阅 Gzip 文档

可能有点晚了,但这有什么不对吗?

import tempfile
with tempfile.NamedTemporaryFile(dir='/tmp', delete=False) as tmpfile:
temp_file_name = tmpfile.name
f = gzip.open(temp_file_name ,'wb')

我认为最简单、最安全的方法是这样的:

path = os.path.join(tempfile.mkdtemp(), 'something')

创建了一个只有您可以访问的临时目录,所以应该没有安全问题,但是不会在其中创建任何文件,所以您可以在该目录中选择您想要创建的任何文件名。请记住,您仍然必须删除文件夹后。

Edit: 在 Python 3中,您现在可以使用 tempfile.TemporaryDirectory()作为上下文管理器来处理删除操作:

with tempfile.TemporaryDirectory() as tmp:
path = os.path.join(tmp, 'something')
# use path

综合前面的答案,我的解决方案是:

def get_tempfile_name(some_id):
return os.path.join(tempfile.gettempdir(), next(tempfile._get_candidate_names()) + "_" + some_id)

如果不需要的话,让 some_id成为可选的。

我会这样做:

import tempfile
import os.path
import random
import string


def generate_temp_filename() -> str:
random_string = ''.join(random.choices(string.ascii_uppercase + string.digits, k=10))
return os.path.join(tempfile.gettempdir(), random_string)

相对于其他答案的优势:

  • 不依赖于私有函数(以 _开始的函数)
  • 不创建文件或目录
  • 不使用不推荐的函数
from random import sample
from string import digits, ascii_letters
from tempfile import gettempdir
from pathlib import Path


filename = Path(gettempdir()) / ''.join(sample(ascii_letters + digits, 10))
## PosixPath('/tmp/fHyMSeVsY8') or
##
filename = Path(gettempdir()).joinpath(''.join(sample(ascii_letters + digits, 10))).as_posix()
## '/tmp/fHyMSeVsY8'


f = gzip.open(filename ,'wb')

我们不要想太多:

import os, uuid, tempfile as tf


def make_temp_name(dir = tf.gettempdir()):
return os.path.join(dir, str(uuid.uuid1()))