Генерация имен временных файлов без создания фактического файла в Python

99

Вопрос номер 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 06
@PolyMesh Вы можете избежать состояния гонки, создав временный каталог, а затем используя в нем файл с фиксированным именем. Таким образом, ваша функция принимает каталог, а не файл, и всегда создает один и тот же файл.
DylanYoung 07
используйте 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())это не обязательно возвращает несуществующий путь, поэтому интерфейсы
временных файлов на
1
Можно было использовать публичное tempfile.gettempdir()вместо частного tempfile._get_default_tempdir().
flonk 07
@EmanuelEy Важно помнить, что при использовании tempfile.mkdtempпользователь несет ответственность за удаление временного каталога и его содержимого по завершении работы с ним.
Daniel Braun
48

Я думаю, что самый простой и безопасный способ сделать это примерно так:

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

Создается временный каталог, доступ к которому есть только у вас, поэтому проблем с безопасностью быть не должно, но в нем не будут создаваться файлы, поэтому вы можете просто выбрать любое имя файла, которое хотите создать в этом каталоге.

edit: в Python 3 теперь вы можете использовать tempfile.TemporaryDirectory()в качестве диспетчера контекста удаление за вас:

with tempfile.TemporaryDirectory() as tmp:
  path = os.path.join(tmp, 'something')
  # use path
Алек
источник
1
Как упоминал выше Даниэль Браун: при использовании важно помнить, tempfile.mkdtempчто пользователь несет ответственность за удаление временного каталога и его содержимого по завершении работы с ним.
bitinerant
4
Если вы используете tempfile.TemporaryDirectory()в качестве диспетчера контекста, он будет удален для вас.
gerrit
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() сделай это.

Но учтите, что это устарело. Однако он не создаст файл, и это общедоступная функция в временном файле по сравнению с использованием _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необязательным, если он вам не нужен.

juanmirocks
источник
Опять же, имена кандидатов могут быть недоступны. Это правильный ответ: stackoverflow.com/a/45803022/6387880
j4hangir
1
Однако, скорее всего, нужно создать случайные имена. Тем не менее, конечно, если _get_candidate_names()он не существует, по умолчанию можно использовать какой-нибудь полуслучайный генератор строк. Например какой-то uuid.
juanmirocks
4

Как сказал Йоахим Исакссон в комментариях, если вы просто получите имя, у вас могут возникнуть проблемы, если какая-то другая программа будет использовать это имя раньше, чем ваша программа. Шансы невелики, но не исключены.

Поэтому в этой ситуации безопаснее всего использовать полный конструктор GzipFile (), который имеет подпись GzipFile( [filename[, mode[, compresslevel[, fileobj]]]]). Таким образом, вы можете передать ему открытый fileobj, а также имя файла, если хотите. Подробности смотрите в документации по gzip.

PM 2Ring
источник