Створюйте тимчасові імена файлів, не створюючи власне файл у Python


98

Питання, номер 10501247 , у stackoverflow дає відповідь, як створити тимчасовий файл у Python.
У моєму випадку мені потрібно мати лише тимчасове ім’я файлу.
Виклик tempfile.NamedTemporaryFile () повертає дескриптор файлу після фактичного створення файлу.
Чи є спосіб отримати лише ім'я файлу?

# 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')
...

7
NamedTemporaryFileгарантує унікальне ім'я (можливо), спробувавши його та повторивши спробу, якщо воно існує. Отримання лише імені не гарантує, що ви зможете фактично створити файл пізніше, ви відкриваєте перегоновий стан когось іншого, хто використовує те саме ім'я до вас.
Йоахім Ісакссон

5
@Joachim Правда, тут є умова перегонів, і було б бажано уникати цього. Однак іноді доводиться передавати функції тимчасове ім'я файлу (файл відкривається внутрішньо.) Наявність приємного випадкового імені дає набагато більшу ймовірність того, що умова перегонів не буде проблемою. Я вважаю, що є вагома потреба надати хороше тимчасове ім'я файлу, щоб мінімізувати ймовірність збою в гонці. Звичайно, додавання хорошого префікса та суфікса на основі запущеного процесу та виконуваного завдання забезпечить ще меншу ймовірність зіткнення.
PolyMesh

@PolyMesh Ви можете уникнути стану перегонів, створивши тимчасовий каталог, а потім використовуючи в ньому файл фіксованих імен. Отже, ваша функція приймає каталог, а не файл, і завжди створює той самий файл.
DylanYoung,

використовуйте tarfile і передайте його fileobj
Wyrmwood

Відповіді:


67

Якщо ви хочете лише ім'я тимчасового файлу, ви можете викликати внутрішню функцію тимчасового файлу _get_candidate_names():

import tempfile

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

Повторний дзвінок nextповерне інше ім’я тощо. Це не дасть вам шляху до тимчасової папки. Щоб отримати каталог за замовчуванням 'tmp', використовуйте:

defult_tmp_dir = tempfile._get_default_tempdir()
% results in: /tmp 

3
кращий спосіб створити тимчасовий каталог - temp_dir = tempfile.mkdtemp(prefix='some-prefix_')це безпечний спосіб створити тимчасовий каталог і повернути рядок із абсолютним шляхом.
Емануель Ей

3
Важливо зазначити, що next(tempfile._get_candidate_names())не обов’язково повертається неіснуючий шлях, тому інтерфейси tempfile на рівні користувача можуть спробувати кілька імен, поки не буде знайдено невикористане :
Eli Korvigo

1
Можна використовувати загальнодоступне, tempfile.gettempdir()а не приватне tempfile._get_default_tempdir().
флонк

@EmanuelEy Важливо пам’ятати, tempfile.mkdtempщо користувач несе відповідальність за видалення тимчасового каталогу та його вмісту після завершення роботи з ним.
Даніель Браун

46

Я думаю, що найпростіший, найбезпечніший спосіб зробити це приблизно так:

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

Створюється тимчасовий каталог, до якого маєте доступ лише ви, тому проблем із безпекою бути не повинно, але файли в ньому створюватися не будуть, тому ви можете просто вибрати будь-яке ім’я файлу, яке ви хочете створити в цьому каталозі.

редагувати: У Python 3 тепер ви можете використовувати tempfile.TemporaryDirectory()як менеджер контексту для обробки видалення для вас:

with tempfile.TemporaryDirectory() as tmp:
  path = os.path.join(tmp, 'something')
  # use path

1
Як згадував вище Даніель Браун: Важливо пам’ятати, tempfile.mkdtempщо користувач відповідає за видалення тимчасового каталогу та його вмісту, коли він виконує його.
бітенерант

4
Якщо ви використовуєте tempfile.TemporaryDirectory()як менеджер контексту, він буде видалений для вас.
геррит

17

Можливо, це трохи пізно, але чи є в цьому щось погане?

import tempfile
with tempfile.NamedTemporaryFile(dir='/tmp', delete=False) as tmpfile:
    temp_file_name = tmpfile.name
f = gzip.open(temp_file_name ,'wb')

37
Цей код фактично створить тимчасовий файл, щоб отримати його ім'я, тоді як у запитанні він говорить without creating actual file in Python.
Якуб Кукуль

Це не відповідає на питання
herve

8

tempfile.mktemp() зробити це.

Але зверніть увагу, що це застаріло. Однак файл не створить, і це загальнодоступна функція в tempfile порівняно з використанням _get_candidate_names().

Причиною його припинення є тимчасовий розрив між викликом цього і фактичною спробою створити файл. Однак у моєму випадку ймовірність цього настільки мала, і навіть якщо це не вдасться, це було б прийнятно. Але це залежить від вас, щоб оцінити для вашого випадку використання.


1
"Навіть якщо це не вдасться, це буде прийнятно"; умова перегони - це не просто ризик невдачі, це ризик безпеки (див. tempfile.mktempдокументацію). Тож це не слід вважати прийнятним.
bignose

4
@bignose Це потенційна проблема безпеки. Це залежить від того, що ви хочете зробити, середовища виконання, в якому ви перебуваєте, і т. Д. Це сказало: можливо, буде більш безпечно робити щось на зразок os.path.join(tempfile.mkdtemp(), 'something')Там, принаймні каталог створений (і я припускаю, що належить вам).
Алек

5

Поєднуючи попередні відповіді, моє рішення:

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

Зробіть some_idнеобов’язково, якщо вам це не потрібно.


Знову ж таки, імена кандидатів можуть бути фактично недоступними. Це правильна відповідь: stackoverflow.com/a/45803022/6387880
j4hangir

1
Однак, швидше за все, потрібно створювати випадкові імена. Проте, без сумніву, якщо _get_candidate_names()такого не існує, можна встановити за замовчуванням якийсь напіввипадковий генератор рядків. Наприклад, якийсь uuid.
juanmirocks

4

Як сказав Йоахім Ісакссон у коментарях, якщо ви просто отримаєте ім’я, у вас можуть виникнути проблеми, якщо якась інша програма використовує це ім’я раніше, ніж ваша програма. Шанси невеликі, але не неможливі.

Тож безпечно в цій ситуації використовувати повний конструктор GzipFile (), який має підпис GzipFile( [filename[, mode[, compresslevel[, fileobj]]]]). Таким чином, ви можете передати йому відкритий файлobobj, а також ім'я файлу, якщо хочете. Детальніше див. У документах gzip.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.