Python中生成随机文件名的最佳方法

163
在Python中,生成一些随机文本作为要保存到服务器上的文件名称的前缀,以确保不覆盖原有文件,有哪些好的或最佳的方法呢?谢谢!
15个回答

195
你可以使用UUID模块来生成一个随机字符串:
import uuid
filename = str(uuid.uuid4())

考虑到UUID生成器极不可能产生重复的标识符(在这种情况下是文件名),因此这是一个有效的选择:

只有在未来100年内每秒生成10亿个UUID,才有约50%的概率创建一个重复的UUID。如果地球上的每个人都拥有6亿个UUID,则一个重复的概率约为50%。


23
当您想要一个独特的文件名,但又不想立即创建该文件时,这也非常有用。 - Prof. Falken
25
可以使用 uuid.uuid4().hex 来获取没有短横线(-)的十六进制字符串。 - Rockallite
如果您因为某些原因(例如在工作电脑上)无法访问C盘,那么这也是NamedTemporaryFile()的一个有用替代方法。对我来说就是这种情况,但uuid方法可行,因为它只是一个随机字符串,可以保存在本地文件夹中。 - user3376851

158

Python提供了生成临时文件名的功能,请参见http://docs.python.org/library/tempfile.html。例如:

In [4]: import tempfile

tempfile.NamedTemporaryFile() 的每次调用都会生成一个不同的临时文件,并且可以通过 .name 属性访问其文件名,例如:

In [5]: tf = tempfile.NamedTemporaryFile()
In [6]: tf.name
Out[6]: 'c:\\blabla\\locals~1\\temp\\tmptecp3i'

In [7]: tf = tempfile.NamedTemporaryFile()
In [8]: tf.name
Out[8]: 'c:\\blabla\\locals~1\\temp\\tmpr8vvme'

一旦你拥有了独特的文件名,它可以像任何普通文件一样使用。注意:默认情况下,当文件关闭时,它会被删除。然而,如果delete参数为False,则文件不会自动删除。

完整参数集:

tempfile.NamedTemporaryFile([mode='w+b'[, bufsize=-1[, suffix=''[, prefix='tmp'[, dir=None[, delete=True]]]]]])

在文件创建过程中,可以通过提供多个参数之一来指定临时文件的前缀:

In [9]: tf = tempfile.NamedTemporaryFile(prefix="zz")
In [10]: tf.name
Out[10]: 'c:\\blabla\\locals~1\\temp\\zzrc3pzk'

在此处可以找到有关使用临时文件的其他示例:这里


1
下次我重启电脑,这些文件会被删除吗? - ABCD
32
这个解决方案的问题在于它不仅生成一个文件名,而且还会生成一个已经打开的文件。如果你需要一个新的临时文件名,而这个文件还不存在(例如,用作操作系统命令的输出),那么这种方法就不行了。在这种情况下,你可以使用类似于 str(uuid.uuid4()) 的方法。 - Luca
@Luca 感谢您的补充评论,这很有用,并且已经记录下来以备将来参考。然而,OP明确表示他/她想要保存文件,因此需要打开它,因此这个解决方案提供了这个功能。 - Levon
这要看情况。也许他需要这个名称来构建一个合适的服务器调用。不确定。无论如何,你的回复肯定是更常见的情况。 - Luca

28

常见的做法是将时间戳作为文件名前缀/后缀,以便与该文件建立一些时间上的关系。如果需要更多的唯一性,仍然可以添加一个随机字符串。

import datetime
basename = "mylogfile"
suffix = datetime.datetime.now().strftime("%y%m%d_%H%M%S")
filename = "_".join([basename, suffix]) # e.g. 'mylogfile_120508_171442'

4
在多线程环境中,涉及到一个可能存在竞争条件的步骤:1. 检查文件是否存在;2. 创建文件。如果在你的代码执行步骤1和步骤2之间被其他进程打断,并且这个进程创建了该文件,那么当你的代码恢复时,它将会覆盖该进程创建的文件。 - Li-aung Yip
@Li-aungYip 另外还可以使用6-8个随机字符序列(以防在同一秒钟生成2个文件)。 - bobobobo
@bobobobo:或者你可以使用tempfile模块,它会为你处理这个问题。 :) - Li-aung Yip
我建议添加微秒,即...strftime("%y%m%d_%H%M%S%f") - AstraSerg

13

如果你只需要预定义长度的随机字符串,而不是文件路径,你可以使用类似以下的代码:

>>> import random
>>> import string

>>> file_name = ''.join(random.choice(string.ascii_lowercase) for i in range(16))
>>> file_name
'ytrvmyhkaxlfaugx'

13

该OP请求创建随机的文件名,而不是随机的文件。时间和UUID可能会发生冲突。如果您在单个计算机上工作(而不是共享文件系统),并且您的进程/线程不会互相干扰,则使用os.getpid()获取自己的PID,并将其用作唯一文件名的一个元素。其他进程显然不会得到相同的PID。如果您使用多线程,则需要获取线程ID。如果您的代码有其他方面,其中单个线程或进程可以生成多个不同的临时文件,则可能需要使用另一种技术。滚动索引可以运作(如果您不会保留它们太久或使用太多文件而担心翻转)。在这种情况下,保持全局哈希/索引以便于“活动”文件就足够了。

非常抱歉解释得有些冗长,但这确实取决于您的确切用途。


9

如果您想将原始文件名作为新文件名的一部分保留下来,可以通过使用当前时间的MD5哈希值生成相同长度的唯一前缀:

from hashlib import md5
from time import localtime

def add_prefix(filename):
    prefix = md5(str(localtime()).encode('utf-8')).hexdigest()
    return f"{prefix}_{filename}"

调用add_prefix('style.css')会生成以下序列:
a38ff35794ae366e442a0606e67035ba_style.css
7a5f8289323b0ebfdbc7c840ad3cb67b_style.css

1
避免:Unicode对象必须在哈希之前进行编码。我改为md5(str(localtime())。encode('utf-8'))。hexdigest() - PhoebeB
1
请注意,任何类型的数据(包括时间戳)的哈希本身并不能确保唯一性(就像随机选择的字节序列一样)。 - Peter O.

4

在这里添砖加瓦:

In [19]: tempfile.mkstemp('.png', 'bingo', '/tmp')[1]
Out[19]: '/tmp/bingoy6s3_k.png'

根据Python文档中tempfile.mkstemp的说明,该函数以最安全的方式创建临时文件。请注意,此调用后该文件将存在:
In [20]: os.path.exists(tempfile.mkstemp('.png', 'bingo', '/tmp')[1])
Out[20]: True

3
由于每秒钟日期和时间都会发生变化,因此您需要将date-time与uuid(通用唯一标识符)连接起来。以下是完整的代码:
   import uuid
   imageName = '{}{:-%Y%m%d%H%M%S}.jpeg'.format(str(uuid.uuid4().hex), datetime.now())

2
虽然这段代码可能解决了问题,但是包括解释它如何以及为什么解决了问题将有助于提高您的帖子质量,并可能导致更多的赞。请记住,您正在回答未来读者的问题,而不仅仅是现在提问的人。请[编辑]您的答案以添加解释并指出适用的限制和假设。 - rizerphe

2
我发现以下解决方案带来了相当大的好处。
我需要将成千上万张图片存储在远程服务器的一个目录中。我们使用的服务器空间有问题,并且这些图片中很多经常是重复的。因此,我找到了一个巧妙的解决方案:使用图像的SHA值生成文件名,并以此名称存储文件。如果它覆盖了一个文件,那就意味着该文件是重复的,所以覆盖它也没关系。SHA256被认为在物理上无法产生碰撞,所以您可以永远放心使用它。
import hashlib

image_path = '/tmp/my_image.png'
with open(image_path, 'rb') as f:
    image_bytes = f.read()

file_name = f'{hashlib.sha256(image_bytes).hexdigest()}.png'
with open(filename, 'wb') as ff:
    ff.write(image_bytes)

如果以下情况适用于您,请使用此方法:

  1. 您不关心文件的创建日期。
  2. 您的系统不依赖于重复的文件。
  3. 您不需要通过文件名来搜索图像(那样会很糟糕)。

如果您保存的文件几乎肯定永远不会产生相同的SHA值,那么此方法对您也几乎没有好处。但是,如果您需要保存数千个文件并确保它们不被覆盖(除了重复文件),此方法仍然可能有用。


1

我个人希望我的文本不仅是随机/独特的,而且也要美观,这就是我喜欢hashids库的原因,它可以从整数生成漂亮的随机文本。

可以通过pip install hashids进行安装。

代码片段:

import hashids
hashids = hashids.Hashids(salt="this is my salt", )
print hashids.encode(1, 2, 3)
>>> laHquq

简要描述:

Hashids是一个小型的开源库,可以从数字中生成短、唯一、非连续的ID。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接