La mejor manera de generar nombres de archivos aleatorios en Python

97

En Python, ¿cuál es una buena o la mejor manera de generar un texto aleatorio para anteponer a un archivo (nombre) que estoy guardando en un servidor, solo para asegurarme de que no se sobrescriba? ¡Gracias!

Zallarak
fuente

Respuestas:

109

Python tiene funciones para generar nombres de archivos temporales, consulte http://docs.python.org/library/tempfile.html . Por ejemplo:

In [4]: import tempfile

Cada llamada a tempfile.NamedTemporaryFile()da como resultado un archivo temporal diferente, y se puede acceder a su nombre con el .nameatributo, por ejemplo:

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'

Una vez que tenga el nombre de archivo único, puede utilizarlo como cualquier archivo normal. Nota : De forma predeterminada, el archivo se eliminará cuando se cierre. Sin embargo, si el deleteparámetro es Falso, el archivo no se elimina automáticamente.

Conjunto completo de parámetros:

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

También es posible especificar el prefijo para el archivo temporal (como uno de los varios parámetros que se pueden proporcionar durante la creación del archivo):

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

Puede encontrar ejemplos adicionales para trabajar con archivos temporales aquí

Levon
fuente
1
¿Se eliminarán esos archivos la próxima vez que reinicie mi máquina?
HelloWorld
15
El problema con esta solución es que genera no solo un nombre de archivo, sino también un archivo que ya está abierto. Si necesita un nombre de archivo temporal para un archivo nuevo que aún no existe (por ejemplo, para usarlo como salida de un comando del sistema operativo), esto no es suficiente. En ese caso, puede hacer algo como str (uuid.uuid4 ()).
Luca
@Luca Gracias por el comentario adicional, que es útil y se anota para referencia futura. Sin embargo, OP declaró claramente que quería guardar un archivo, por lo tanto, necesita abrirlo, por lo que esta solución lo permite.
Levon
Depende. Quizás necesite el nombre para construir una llamada de servidor adecuada. No estoy seguro. En cualquier caso, su respuesta es sin duda el caso más común.
Luca
108

Puede usar el módulo UUID para generar una cadena aleatoria:

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

Esta es una opción válida, dado que es muy poco probable que un generador de UUID produzca un identificador duplicado (un nombre de archivo, en este caso):

Solo después de generar mil millones de UUID por segundo durante los próximos 100 años, la probabilidad de crear solo un duplicado sería de aproximadamente el 50%. La probabilidad de un duplicado sería de aproximadamente el 50% si cada persona en la tierra posee 600 millones de UUID.

Óscar López
fuente
17
esto también es muy útil cuando desea un nombre de archivo único, pero no desea que se cree todavía.
Prof. Falken
15
O use uuid.uuid4().hexpara obtener una cadena hexadecimal sin guiones ( -).
Rockallite
17

un enfoque común es agregar una marca de tiempo como prefijo / sufijo al nombre del archivo para tener alguna relación temporal con el archivo. Si necesita más singularidad, aún puede agregar una cadena aleatoria a esto.

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
fuente
4
En un entorno de subprocesos múltiples, hay una posible condición de carrera involucrada en la secuencia. 1. Test if file exists, 2. create file.Si otro proceso interrumpe el suyo entre los pasos 1 y 2 y crea el archivo, cuando su código se reanude, sobrescribirá el archivo del otro proceso.
Li-aung Yip
@ Li-aungYip Además, también puede utilizar una secuencia de caracteres aleatorios de 6-8 (en caso de que se generen 2 archivos en el mismo segundo).
bobobobo
@bobobobo: O puede usar el tempfilemódulo, que se encarga de esto por usted. :)
Li-aung Yip
Sugeriría agregar microsegundos, es decir...strftime("%y%m%d_%H%M%S%f")
AstraSerg
8

El OP solicitó crear nombres de archivo aleatorios, no archivos aleatorios . Los tiempos y los UUID pueden chocar. Si está trabajando en una sola máquina (no en un sistema de archivos compartido) y su proceso / subproceso no pisoteará a sí mismok, use os.getpid () para obtener su propio PID y utilícelo como un elemento de un nombre de archivo único. Obviamente, otros procesos no obtendrían el mismo PID. Si es multiproceso, obtenga el ID del hilo. Si tiene otros aspectos de su código en los que un solo hilo o proceso podría generar múltiples archivos temporales diferentes, es posible que deba usar otra técnica. Un índice continuo puede funcionar (si no los mantiene durante tanto tiempo o si usa tantos archivos, se preocuparía por la transferencia). En ese caso, sería suficiente mantener un hash / índice global para archivos "activos".

Lo siento por la explicación tan larga, pero depende de su uso exacto.

Puntilla
fuente
8

Si no necesita la ruta del archivo, pero solo la cadena aleatoria que tiene una longitud predefinida, puede usar algo como esto.

>>> import random
>>> import string

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

Si desea conservar el nombre de archivo original como parte del nuevo nombre de archivo, se pueden generar prefijos únicos de longitud uniforme utilizando hashes MD5 de la hora actual:

from hashlib import md5
from time import localtime

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

Las llamadas al add_prefix ('style.css') generan una secuencia como:

a38ff35794ae366e442a0606e67035ba_style.css
7a5f8289323b0ebfdbc7c840ad3cb67b_style.css
Aleš Kotnik
fuente
1
Para evitar: los objetos Unicode deben codificarse antes de aplicar el hash. Cambié a md5 (str (localtime ()). Encode ('utf-8')). Hexdigest ()
PhoebeB
1
Tenga en cuenta que un hash de cualquier tipo de datos (incluida una marca de tiempo) no garantiza la unicidad por sí mismo (como tampoco lo hace una secuencia de bytes elegida al azar).
Peter O.24 de
1

Añadiendo mis dos centavos aquí:

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

Según el documento de python para tempfile.mkstemp, crea un archivo temporal de la manera más segura posible. Tenga en cuenta que el archivo existirá después de esta llamada:

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

Personalmente, prefiero que mi texto no sea solo aleatorio / único, sino también hermoso, por eso me gusta la biblioteca hashids, que genera un texto aleatorio de aspecto agradable a partir de números enteros. Se puede instalar a través

pip install hashids

Retazo:

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

Breve descripción:

Hashids es una pequeña biblioteca de código abierto que genera identificadores cortos, únicos y no secuenciales a partir de números.

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

Puede cambiar 'string.ascii_letters' a cualquier formato de cadena que desee para generar cualquier otro texto, por ejemplo, NO móvil, ID ... ingrese la descripción de la imagen aquí

Freman Zhang
fuente
0
import uuid
   imageName = '{}{:-%Y%m%d%H%M%S}.jpeg'.format(str(uuid.uuid4().hex), datetime.now())
Asad Farooq
fuente
1
Si bien este código puede resolver la pregunta, incluir una explicación de cómo y por qué esto resuelve el problema realmente ayudaría a mejorar la calidad de su publicación y probablemente resultaría en más votos a favor. Recuerde que está respondiendo la pregunta a los lectores en el futuro, no solo a la persona que pregunta ahora. Por favor, editar su respuesta para agregar explicaciones y dar una indicación de lo que se aplican limitaciones y supuestos.
Богдан Опир
-1

Puedes usar el paquete aleatorio:

import random
file = random.random()
anajem
fuente
file = str (random.random ())
anajem
Esto genera números aleatorios, no un texto aleatorio.
user1767754