Najlepszy sposób na generowanie losowych nazw plików w Pythonie

98

W Pythonie, co jest dobrym lub najlepszym sposobem na wygenerowanie losowego tekstu do dołączenia przed plikiem (nazwą), który zapisuję na serwerze, aby upewnić się, że nie zostanie nadpisany. Dziękuję Ci!

zallarak
źródło

Odpowiedzi:

110

Python ma narzędzia do generowania tymczasowych nazw plików, zobacz http://docs.python.org/library/tempfile.html . Na przykład:

In [4]: import tempfile

Każde wywołanie tempfile.NamedTemporaryFile()powoduje powstanie innego pliku tymczasowego, a do jego nazwy można uzyskać dostęp za pomocą .nameatrybutu, np .:

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'

Po uzyskaniu unikalnej nazwy pliku można go używać jak każdego zwykłego pliku. Uwaga : Domyślnie plik zostanie usunięty po zamknięciu. Jeśli jednak deleteparametr ma wartość False, plik nie jest automatycznie usuwany.

Pełny zestaw parametrów:

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

można również określić prefiks dla pliku tymczasowego (jako jeden z różnych parametrów, które można podać podczas tworzenia pliku):

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

Dodatkowe przykłady pracy z plikami tymczasowymi można znaleźć tutaj

Levon
źródło
1
Czy te pliki zostaną usunięte, gdy następnym razem uruchomię ponownie komputer?
SmallChess
15
Problem z tym rozwiązaniem polega na tym, że generuje nie tylko nazwę pliku, ale także plik, który jest już otwarty. Jeśli potrzebujesz tymczasowej nazwy pliku dla nowego, jeszcze nieistniejącego pliku (np. Do użycia jako wyjście polecenia os), to nie wystarczy. W takim przypadku możesz zrobić coś takiego jak str (uuid.uuid4 ()).
Luca
@Luca Dzięki za dodatkowy komentarz, który jest przydatny i uwzględniony w przyszłości. Jednak OP wyraźnie stwierdził, że chce zapisać plik, dlatego musi go otworzyć, więc to rozwiązanie zapewnia to.
Levon
To zależy. Być może potrzebuje nazwy, aby skonstruować odpowiednie wywołanie serwera. Niepewny. W każdym razie twoja odpowiedź jest z pewnością bardziej powszechnym przypadkiem.
Luca
112

Możesz użyć modułu UUID do wygenerowania losowego ciągu:

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

Jest to słuszny wybór, biorąc pod uwagę, że jest bardzo mało prawdopodobne, aby generator UUID wygenerował zduplikowany identyfikator (w tym przypadku nazwę pliku):

Dopiero po wygenerowaniu 1 miliarda identyfikatorów UUID co sekundę przez następne 100 lat prawdopodobieństwo utworzenia tylko jednego duplikatu wyniosłoby około 50%. Prawdopodobieństwo jednego duplikatu wyniosłoby około 50%, gdyby każda osoba na Ziemi posiadała 600 milionów identyfikatorów UUID.

Óscar López
źródło
17
jest to również bardzo przydatne, gdy chcesz mieć unikalną nazwę pliku, ale nie chcesz, aby został jeszcze utworzony.
Prof. Falken
15
Lub użyj, uuid.uuid4().hexaby uzyskać ciąg szesnastkowy bez myślników ( -).
Rockallite
17

powszechnym podejściem jest dodanie sygnatury czasowej jako przedrostka / przyrostka do nazwy pliku, aby uzyskać pewną tymczasową relację z plikiem. Jeśli potrzebujesz większej wyjątkowości, nadal możesz dodać do tego losowy ciąg.

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
źródło
4
W środowisku wielowątkowym w sekwencji może 1. Test if file exists, 2. create file.wystąpić sytuacja wyścigu. Jeśli inny proces przerwie twój między krokami 1 i 2 i utworzy plik, po wznowieniu kodu nadpisze plik innego procesu.
Li-aung Yip
@ Li-aungYip Dodatkowo można również użyć 6-8 losowej sekwencji znaków (w przypadku 2 plików generowanych w tej samej sekundzie).
bobobobo
@bobobobo: Lub możesz użyć tempfilemodułu, który zajmie się tym za Ciebie. :)
Li-aung Yip
Proponuję dodać mikrosekundy, tj....strftime("%y%m%d_%H%M%S%f")
AstraSerg
8

OP zażądał utworzenia losowych nazw plików, a nie plików losowych . Czasy i identyfikatory UUID mogą się kolidować. Jeśli pracujesz na pojedynczej maszynie (nie na współdzielonym systemie plików) i twój proces / wątek nie nadepnie na siebiek, użyj os.getpid (), aby uzyskać własny PID i użyj go jako elementu unikalnej nazwy pliku. Inne procesy oczywiście nie otrzymałyby tego samego PID. Jeśli jesteś wielowątkowy, uzyskaj identyfikator wątku. Jeśli masz inne aspekty kodu, w których pojedynczy wątek lub proces może generować wiele różnych plików tymczasowych, może być konieczne użycie innej techniki. Rolling index może działać (jeśli nie przechowujesz ich tak długo lub nie używasz tak wielu plików, że martwisz się o przewijanie). W takim przypadku wystarczyłoby utrzymywanie globalnego skrótu / indeksu dla „aktywnych” plików.

Tak mi przykro z powodu długich wyjaśnień, ale zależy to od dokładnego użycia.

Ćwiek
źródło
8

Jeśli nie potrzebujesz ścieżki do pliku, ale tylko losowego ciągu o określonej długości, możesz użyć czegoś takiego.

>>> import random
>>> import string

>>> file_name = ''.join(random.choice(string.ascii_lowercase) for i in range(16))
>>> file_name
'ytrvmyhkaxlfaugx'
4xy
źródło
7

Jeśli chcesz zachować oryginalną nazwę pliku jako część nowej nazwy pliku, unikalne przedrostki o jednakowej długości można wygenerować za pomocą skrótów MD5 aktualnego czasu:

from hashlib import md5
from time import localtime

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

Wywołania add_prefix („style.css”) generują sekwencję taką jak:

a38ff35794ae366e442a0606e67035ba_style.css
7a5f8289323b0ebfdbc7c840ad3cb67b_style.css
Aleš Kotnik
źródło
1
Aby uniknąć: obiekty Unicode muszą być zakodowane przed haszowaniem Zmieniłem na md5 (str (localtime ()). Encode ('utf-8')). Hexdigest ()
PhoebeB
1
Zwróć uwagę, że skrót dowolnego rodzaju danych (w tym znacznik czasu) sam w sobie nie zapewnia unikalności (podobnie jak losowo wybrana sekwencja bajtów).
Peter O.
1

Dodaję tutaj moje dwa centy:

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

Zgodnie z dokumentacją Pythona dla tempfile.mkstemp, tworzy plik tymczasowy w najbezpieczniejszy możliwy sposób. Pamiętaj, że plik będzie istniał po tym wywołaniu:

In [20]: os.path.exists(tempfile.mkstemp('.png', 'bingo', '/tmp')[1])
Out[20]: True
shahins
źródło
1

Osobiście wolę, aby mój tekst był nie tylko przypadkowy / unikalny, ale także piękny, dlatego podoba mi się hashids lib, który generuje ładnie wyglądający losowy tekst z liczb całkowitych. Można zainstalować przez

pip install hashids

Skrawek:

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

Krótki opis:

Hashids to mała biblioteka typu open source, która generuje krótkie, unikalne, niesekwencyjne identyfikatory z liczb.

user1767754
źródło
0
>>> import random
>>> import string    
>>> alias = ''.join(random.choice(string.ascii_letters) for _ in range(16))
>>> alias
'WrVkPmjeSOgTmCRG'

Możesz zmienić `` string.ascii_letters '' na dowolny format ciągu, tak jak chcesz generować dowolny inny tekst, na przykład numer telefonu komórkowego, identyfikator ... wprowadź opis obrazu tutaj

Freman Zhang
źródło
0
import uuid
   imageName = '{}{:-%Y%m%d%H%M%S}.jpeg'.format(str(uuid.uuid4().hex), datetime.now())
Asad Farooq
źródło
1
Chociaż ten kod może rozwiązać problem, w tym wyjaśnienie, jak i dlaczego to rozwiązuje problem, naprawdę pomogłoby poprawić jakość twojego posta i prawdopodobnie zaowocowałoby większą liczbą pozytywnych głosów. Pamiętaj, że odpowiadasz na pytanie do czytelników w przyszłości, a nie tylko osoba, która zapyta teraz. Proszę edytować swoje odpowiedzi, aby dodać wyjaśnień i dać wskazówkę co zastosować ograniczenia i założenia.
Богдан Опир
-1

Możesz użyć losowego pakietu:

import random
file = random.random()
anajem
źródło
file = str (random.random ())
anajem
To jest generowanie liczb losowych, a nie losowego tekstu.
user1767754