生成临时文件名,而无需在Python中创建实际文件


98

stackoverflow中的编号为10501247的问题给出了如何在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')
...

7
NamedTemporaryFile(可能)通过尝试并如果存在则重试来保证唯一的名称。仅获得名称并不能保证您以后可以实际创建该文件,因为您在使用其他人之前使用相同名称的竞争条件很容易。
Joachim Isaksson 2014年

5
@Joachim是的,这里有一个比赛条件,最好避免这种情况。但是,有时您必须将一个临时文件名传递给一个函数(文件打开在内部发生。)拥有一个很好的随机名称可以使竞争条件成为非问题的可能性要大得多。我认为确实有必要提供一个良好的临时文件名,以最大程度地减少竞争条件失败的可能性。当然,根据正在运行的进程和正在执行的任务添加良好的前缀和后缀将提供更少的冲突机会。
PolyMesh

@PolyMesh您可以通过创建一个临时目录,然后在其中使用固定名称文件来避免出现竞争状况。因此,您的函数接受目录而不是文件,并始终创建相同的文件。
DylanYoung

使用tar文件,并将它传递的FileObj文件
Wyrmwood

Answers:


67

如果只需要一个临时文件名,则可以调用内部tempfile函数_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 

3
创建临时目录的一种更好方法是temp_dir = tempfile.mkdtemp(prefix='some-prefix_')安全地创建一个临时目录并返回带有绝对路径的字符串。
伊曼纽尔·伊(Emanuel Ey)2015年

3
需要指出的是,next(tempfile._get_candidate_names())不一定返回不存在的路径,这就是为什么用户级临时文件接口可以尝试使用多个名称直到找到未使用的名称的原因:
Eli Korvigo

1
可以使用公共tempfile.gettempdir()而不是私有tempfile._get_default_tempdir()
flonk

@EmanuelEy请记住,使用tempfile.mkdtemp用户负责删除临时目录及其后的内容非常重要。
丹尼尔·布劳恩

46

我认为最简单,最安全的方法是:

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

将创建一个只有您可以访问的临时目录,因此应该没有安全性问题,但是不会创建任何文件,因此您可以选择要在该目录中创建的任何文件名。

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

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

1
正如丹尼尔·布劳恩(Daniel Braun)上文所述:重要的是要记住,使用tempfile.mkdtemp用户时应负责删除临时目录及其内容。
bitinerant

4
如果tempfile.TemporaryDirectory()用作上下文管理器,它将为您删除。
Gerrit

17

可能有点晚了,但是这有什么问题吗?

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

37
该代码实际上将创建临时文件以获取其名称,而在问题中它说without creating actual file in Python
雅各布·库库尔

这不能回答问题
herve

8

tempfile.mktemp() 做这个。

但是请注意,它已被弃用。但是,它不会创建文件,与使用相比,它是tempfile中的公共函数_get_candidate_names()

不建议使用它的原因是由于调用此方法与实际尝试创建文件之间存在时间间隔。但是在我看来,这样做的机会非常渺茫,即使失败了也可以接受。但是由您来评估用例。


1
“即使失败,也可以接受”;竞争状况不仅是失败的风险,还是安全风险(请参阅tempfile.mktemp文档)。因此,这不应被认为是可以接受的。
bignose

4
@bignose这是一个潜在的安全问题。这取决于您要执行的操作,所处的执行环境等。这就是说:做这样的事情可能更安全,因为os.path.join(tempfile.mkdtemp(), 'something')至少创建了目录(我想由您拥有)。
亚历克

5

结合先前的答案,我的解决方案是:

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

some_id如果不需要,请设置为可选。


同样,候选名称可能实际上不可用。这是正确的答案:stackoverflow.com/a/45803022/6387880
j4hangir

1
但是,可能需要创建随机名称。但是,可以肯定的是,如果_get_candidate_names()不存在,则可以默认使用某种半随机字符串生成器。例如一些uuid。
juanmirocks

4

正如Joachim Isaksson在评论中说的那样,如果您只是得到一个名字,那么如果某个其他程序在您的程序之前恰好使用了该名字,则可能会遇到问题。机会渺茫,但并非不可能。

因此,在这种情况下,安全的做法是使用具有签名的完整GzipFile()构造函数GzipFile( [filename[, mode[, compresslevel[, fileobj]]]])。因此,您可以根据需要向其传递打开的fileobj和文件名。有关详细信息,请参见gzip文档。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.