Melhor maneira de gerar nomes de arquivo aleatórios em Python

95

Em Python, qual é uma boa ou a melhor maneira de gerar algum texto aleatório para preceder a um arquivo (nome) que estou salvando em um servidor, apenas para ter certeza de que não será sobrescrito. Obrigado!

Zallarak
fonte

Respostas:

109

Python possui recursos para gerar nomes de arquivos temporários, consulte http://docs.python.org/library/tempfile.html . Por exemplo:

In [4]: import tempfile

Cada chamada para tempfile.NamedTemporaryFile()resulta em um arquivo temporário diferente, e seu nome pode ser acessado com o .nameatributo, por exemplo:

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'

Depois de obter o nome do arquivo exclusivo, ele pode ser usado como qualquer arquivo normal. Nota : Por padrão, o arquivo será excluído quando for fechado. No entanto, se o deleteparâmetro for False, o arquivo não será excluído automaticamente.

Conjunto completo de parâmetros:

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

também é possível especificar o prefixo para o arquivo temporário (como um dos vários parâmetros que podem ser fornecidos durante a criação do arquivo):

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

Exemplos adicionais para trabalhar com arquivos temporários podem ser encontrados aqui

Levon
fonte
1
Esses arquivos seriam excluídos na próxima vez que eu reiniciar minha máquina?
HelloWorld
15
O problema dessa solução é que ela gera não apenas um nome de arquivo, mas também um arquivo que já está aberto. Se você precisar de um nome de arquivo temporário para um arquivo novo, ainda não existente (por exemplo, para usar como saída de um comando os), isso não será suficiente. Nesse caso, você pode fazer algo como str (uuid.uuid4 ()).
Luca
@Luca Obrigado pelo comentário adicional, que é útil e anotado para referência futura. No entanto, OP afirmou claramente que queria salvar um arquivo, portanto, precisava abri-lo, então esta solução prevê isso.
Levon
Depende. Talvez ele precise do nome para construir uma chamada de servidor apropriada. Não tenho certeza. De qualquer forma, sua resposta é certamente o caso mais comum.
Luca
105

Você pode usar o módulo UUID para gerar uma string aleatória:

import uuid
filename = str(uuid.uuid4())

Esta é uma escolha válida, visto que é extremamente improvável que um gerador de UUID produza um identificador duplicado (um nome de arquivo, neste caso):

Somente depois de gerar 1 bilhão de UUIDs a cada segundo durante os próximos 100 anos, a probabilidade de criar apenas uma duplicata seria de cerca de 50%. A probabilidade de uma duplicata seria de cerca de 50% se cada pessoa na Terra possuísse 600 milhões de UUIDs.

Óscar López
fonte
16
isso também é muito útil quando você deseja um nome de arquivo exclusivo, mas não deseja que ele seja criado ainda.
Prof. Falken
14
Ou use uuid.uuid4().hexpara obter uma string hexadecimal sem traços ( -).
Rockallite
17

uma abordagem comum é adicionar um carimbo de data / hora como prefixo / sufixo ao nome do arquivo para ter alguma relação temporal com o arquivo. Se precisar de mais exclusividade, você ainda pode adicionar uma string aleatória a isso.

import datetime
basename = "mylogfile"
suffix = datetime.datetime.now().strftime("%y%m%d_%H%M%S")
filename = "_".join([basename, suffix]) # e.g. 'mylogfile_120508_171442'
moooeeeep
fonte
4
Em um ambiente multithread, há uma possível condição de corrida envolvida na sequência. 1. Test if file exists, 2. create file.Se outro processo interromper o seu entre as etapas 1 e 2 e criar o arquivo, quando seu código for retomado, ele substituirá o arquivo do outro processo.
Li-aung Yip
@ Li-aungYip Além disso, também pode usar sequência de caracteres aleatórios de 6-8 (no caso de 2 arquivos serem gerados no mesmo segundo).
bobobobo
@bobobobo: Ou você pode usar o tempfilemódulo, que faz isso para você. :)
Li-aung Yip,
Eu sugiro adicionar microssegundos, ou seja...strftime("%y%m%d_%H%M%S%f")
AstraSerg
8

O OP solicitou a criação de nomes de arquivos aleatórios, não arquivos aleatórios . Vezes e UUIDs podem colidir. Se você estiver trabalhando em uma única máquina (não em um sistema de arquivos compartilhado) e seu processo / thread não piscar em si mesmo, use os.getpid () para obter seu próprio PID e use-o como um elemento de um nome de arquivo exclusivo. Outros processos obviamente não obteriam o mesmo PID. Se você for multithread, obtenha o id do thread. Se você tiver outros aspectos de seu código em que um único thread ou processo pode gerar vários arquivos temporários diferentes, pode ser necessário usar outra técnica. Um índice rolante pode funcionar (se você não os mantiver por tanto tempo ou usar tantos arquivos, você se preocuparia com o rollover). Manter um hash / índice global para arquivos "ativos" seria suficiente neste caso.

Desculpe pela explicação demorada, mas depende do seu uso exato.

Brad
fonte
8

Se você não precisa do caminho do arquivo, mas apenas da string aleatória com comprimento predefinido, você pode usar algo assim.

>>> import random
>>> import string

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

Se você quiser preservar o nome do arquivo original como parte do novo nome de arquivo, prefixos exclusivos de comprimento uniforme podem ser gerados usando hashes MD5 da hora atual:

from hashlib import md5
from time import localtime

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

Chamadas para add_prefix ('style.css') geram sequência como:

a38ff35794ae366e442a0606e67035ba_style.css
7a5f8289323b0ebfdbc7c840ad3cb67b_style.css
Aleš Kotnik
fonte
1
Para evitar: Objetos Unicode devem ser codificados antes de fazer o hash eu mudei para md5 (str (localtime ()). Encode ('utf-8')). Hexdigest ()
PhoebeB
1
Observe que um hash de qualquer tipo de dado (incluindo um carimbo de data / hora) não garante exclusividade por si só (não mais do que uma sequência de bytes escolhida aleatoriamente).
Peter O.
1

Adicionando meus dois centavos aqui:

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

De acordo com o documento python para tempfile.mkstemp, ele cria um arquivo temporário da maneira mais segura possível. Observe que o arquivo existirá após esta chamada:

In [20]: os.path.exists(tempfile.mkstemp('.png', 'bingo', '/tmp')[1])
Out[20]: True
Shahins
fonte
1

Eu pessoalmente prefiro que meu texto não seja apenas aleatório / único, mas bonito também, é por isso que gosto da biblioteca de hashids, que gera um texto aleatório bonito a partir de inteiros. Pode ser instalado através de

pip install hashids

Snippet:

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

Pequena descrição:

Hashids é uma pequena biblioteca de código aberto que gera ids curtos, exclusivos e não sequenciais a partir de números.

user1767754
fonte
0
>>> import random
>>> import string    
>>> alias = ''.join(random.choice(string.ascii_letters) for _ in range(16))
>>> alias
'WrVkPmjeSOgTmCRG'

Você pode alterar 'string.ascii_letters' para qualquer formato de string conforme desejar para gerar qualquer outro texto, por exemplo, móvel NO, ID ... insira a descrição da imagem aqui

Freman Zhang
fonte
0
import uuid
   imageName = '{}{:-%Y%m%d%H%M%S}.jpeg'.format(str(uuid.uuid4().hex), datetime.now())
Asad Farooq
fonte
1
Embora este código possa resolver a questão, incluir uma explicação de como e por que isso resolve o problema realmente ajudaria a melhorar a qualidade de sua postagem e provavelmente resultaria em mais votos positivos. Lembre-se de que você está respondendo às perguntas dos leitores no futuro, não apenas da pessoa que está perguntando agora. Por favor edite sua resposta para adicionar explicações e dar uma indicação do que limitações e premissas se aplicam.
Богдан Опир
-1

Você pode usar o pacote aleatório:

import random
file = random.random()
anajem
fonte
file = str (random.random ())
anajem
Isso está gerando números aleatórios, não um texto aleatório.
user1767754