Generuj tymczasowe nazwy plików bez tworzenia rzeczywistego pliku w Pythonie

104

Pytanie numer 10501247 w stackoverflow daje odpowiedź, jak utworzyć plik tymczasowy w Pythonie.
W moim przypadku potrzebuję tylko tymczasowej nazwy pliku.
Wywołanie tempfile.NamedTemporaryFile () zwraca uchwyt pliku po jego utworzeniu.
Czy jest sposób, aby uzyskać tylko nazwę pliku?

# 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')
...
Wzgórze
źródło
7
NamedTemporaryFilegwarantuje unikalną nazwę (prawdopodobnie), wypróbowując ją i ponawiając próbę, jeśli istnieje. Uzyskanie samej nazwy nie gwarantuje, że będziesz mógł faktycznie utworzyć plik później, otwierasz się na warunki rasy kogoś innego, kto używa tej samej nazwy przed tobą.
Joachim Isaksson
5
@Joachim Prawda, jest tu sytuacja wyścigu i lepiej byłoby tego uniknąć. Czasami jednak musisz przekazać tymczasową nazwę pliku do funkcji (otwarcie pliku dzieje się wewnętrznie). Posiadanie ładnie losowej nazwy daje znacznie większe prawdopodobieństwo, że stan wyścigu nie będzie problemem. Myślę, że istnieje uzasadniona potrzeba podania dobrej tymczasowej nazwy pliku, aby zminimalizować ryzyko niepowodzenia wyścigu. Oczywiście dodanie dobrego prefiksu i sufiksu w oparciu o uruchomiony proces i wykonywane zadanie zapewni jeszcze mniejszą szansę na kolizję.
PolyMesh
@PolyMesh Możesz uniknąć sytuacji wyścigu, tworząc katalog tymczasowy, a następnie używając w nim pliku o ustalonej nazwie. Twoja funkcja akceptuje katalog zamiast pliku i zawsze tworzy ten sam plik.
DylanYoung
użyj pliku
tar

Odpowiedzi:

67

Jeśli chcesz mieć tylko nazwę pliku tymczasowego, możesz wywołać funkcję wewnętrznego pliku tymczasowego _get_candidate_names():

import tempfile

temp_name = next(tempfile._get_candidate_names())
% e.g. px9cp65s

nextPonowne wywołanie zwróci inną nazwę itp. Nie daje to ścieżki do folderu tymczasowego. Aby uzyskać domyślny katalog „tmp”, użyj:

defult_tmp_dir = tempfile._get_default_tempdir()
% results in: /tmp 
Marcin
źródło
3
Lepszym sposobem na utworzenie katalogu tymczasowego jest temp_dir = tempfile.mkdtemp(prefix='some-prefix_')bezpieczne utworzenie katalogu tymczasowego i zwrócenie ciągu znaków z bezwzględną ścieżką.
Emanuel Ey
3
Ważne jest, aby podkreślić, że next(tempfile._get_candidate_names())niekoniecznie zwraca nieistniejącą ścieżkę, dlatego interfejsy plików tymczasowych na poziomie użytkownika mogą wypróbować kilka nazw, dopóki nie zostanie znaleziona nieużywana :
Eli Korvigo,
1
Można by użyć publicznego tempfile.gettempdir()zamiast prywatnego tempfile._get_default_tempdir().
flonk
@EmanuelEy Należy pamiętać, że podczas używania tempfile.mkdtempużytkownik jest odpowiedzialny za usunięcie katalogu tymczasowego i jego zawartości po zakończeniu korzystania z niego.
Daniel Braun,
48

Myślę, że najłatwiejszym i najbezpieczniejszym sposobem na zrobienie tego jest coś takiego:

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

Tworzony jest katalog tymczasowy, do którego tylko Ty masz dostęp, więc nie powinno być problemów z bezpieczeństwem, ale nie będą w nim tworzone żadne pliki, więc możesz po prostu wybrać dowolną nazwę pliku, którą chcesz utworzyć w tym katalogu.

edycja: w Pythonie 3 możesz teraz używać tempfile.TemporaryDirectory()jako menedżera kontekstu do obsługi usuwania:

with tempfile.TemporaryDirectory() as tmp:
  path = os.path.join(tmp, 'something')
  # use path
Alec
źródło
1
Jak wspomniał Daniel Braun powyżej: Należy pamiętać, że podczas korzystania tempfile.mkdtempużytkownik jest odpowiedzialny za usunięcie katalogu tymczasowego i jego zawartości po zakończeniu korzystania z niego.
bitinerant
5
Jeśli używasz tempfile.TemporaryDirectory()jako menedżera kontekstu, zostanie on usunięty.
gerrit
16

Może być trochę za późno, ale czy jest w tym coś złego?

import tempfile
with tempfile.NamedTemporaryFile(dir='/tmp', delete=False) as tmpfile:
    temp_file_name = tmpfile.name
f = gzip.open(temp_file_name ,'wb')
Russell
źródło
39
Ten kod faktycznie utworzy plik tymczasowy, aby uzyskać jego nazwę, podczas gdy w pytaniu mówi without creating actual file in Python.
Jakub Kukul
To nie odpowiada na pytanie
herve
9

tempfile.mktemp() Zrób to.

Ale pamiętaj, że jest przestarzały. Jednak nie utworzy pliku i jest to funkcja publiczna w pliku tymczasowym w porównaniu z użyciem _get_candidate_names().

Powodem, dla którego jest przestarzały, jest przerwa czasowa między wywołaniem tego a faktyczną próbą utworzenia pliku. Jednak w moim przypadku szansa na to jest niewielka i nawet gdyby się nie udała, to byłoby to do zaakceptowania. Ale to do Ciebie należy ocena dla Twojego przypadku.

Zitrax
źródło
1
„Nawet gdyby to się nie udało, byłoby to do przyjęcia”; stan wyścigu to nie tylko ryzyko niepowodzenia, ale także zagrożenie bezpieczeństwa (patrz tempfile.mktempdokumentacja). Więc to nie powinno być uważane za akceptowalne.
bignose
5
@bignose To potencjalny problem z bezpieczeństwem. To zależy od tego, co chcesz zrobić, środowiska wykonawczego, w którym się znajdujesz, itp. To powiedziawszy: może być bezpieczniej zrobić coś takiego, jak os.path.join(tempfile.mkdtemp(), 'something')Tam przynajmniej został utworzony katalog (i zakładam, że jest on Twoją własnością).
Alec
5

Łącząc poprzednie odpowiedzi, moje rozwiązanie to:

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

Ustaw some_idopcjonalne, jeśli nie są potrzebne.

juanmirocks
źródło
Nazwy kandydatów mogą nie być w rzeczywistości dostępne. To jest poprawna odpowiedź: stackoverflow.com/a/45803022/6387880
j4hangir
1
Jednak prawdopodobnie trzeba stworzyć losowe nazwy. Niemniej jednak, aby być pewnym, jeśli _get_candidate_names()nie istnieje, można domyślnie użyć jakiegoś półlosowego generatora ciągów. Na przykład jakiś uuid.
juanmirocks
4

Jak powiedział Joachim Isaksson w komentarzach, jeśli otrzymujesz tylko nazwę, możesz mieć problemy, jeśli jakiś inny program użyje tej nazwy wcześniej niż twój program. Szanse są niewielkie, ale nie niemożliwe.

Dlatego bezpieczną rzeczą do zrobienia w tej sytuacji jest użycie pełnego konstruktora GzipFile (), który ma podpis GzipFile( [filename[, mode[, compresslevel[, fileobj]]]]). Możesz więc przekazać mu otwarty plikobj i, jeśli chcesz, również nazwę pliku. Szczegółowe informacje można znaleźć w dokumentacji gzip.

PM 2Ring
źródło