В python сделать временный файл в том же каталоге, что и другой файл?

Мне нужно обновить файл. Читаю и выписываю с изменениями. Однако я бы предпочел записать во временный файл и переименовать его на место.

temp = tempfile.NamedTemporaryFile()
tempname = temp.name
temp.write(new_data)
temp.close()
os.rename(tempname, data_file_name)

Проблема в том, что tempfile.NamedTemporaryFile() создает временный файл в /tmp, который является другой файловой системой. Это означает, что os.rename() не работает. Если вместо этого я использую shlib.move(), то у меня нет атомарного обновления, которое предоставляет «mv» (для файлов в той же файловой системе, yadda, yadda и т. д.)

Я знаю, что tempfile.NamedTemporaryFile() принимает параметр "dir", но data_file_name может быть "foo.txt", и в этом случае dir='.'; или data_file_name может быть "/path/to/the/data/foo.txt", и в этом случае dir="/path/to/the/data".

Мне бы очень хотелось, чтобы временный файл был data_file_name + «некоторые случайные данные». Преимущество этого было бы в том, что он потерпел бы неудачу, оставив после себя полезные подсказки.

Предложения?


person TomOnTime    schedule 05.01.2012    source источник
comment
Почему вы вообще используете временный файл, если вы не хотите, чтобы он помещался в каталог для временных файлов? Что говорит против использования обычных файлов?   -  person David Zwicker    schedule 05.01.2012
comment
Дэвид: Я хочу использовать временный файл, потому что хочу, чтобы обновление было атомарным (или настолько атомарным, насколько это возможно с помощью os.rename()). То есть, если файловая система заполнится или будет какая-то другая проблема, я не хочу, чтобы файл был записан наполовину.   -  person TomOnTime    schedule 06.01.2012
comment
Что ж, этого может быть трудно достичь, поскольку вы никогда не знаете, находятся ли файлы, записанные в другую папку, в той же файловой системе, что и ваш локальный каталог. Я вижу преимущество организации вашего вывода в каком-то коммите. Чтобы быть относительно уверенным, что это так, я бы, вероятно, управлял своим собственным временным каталогом, хотя тогда вы также позаботитесь об очистке этой папки.   -  person David Zwicker    schedule 06.01.2012


Ответы (5)


Вы можете использовать:

  • prefix, чтобы временный файл начинался с того же имени, что и исходный файл.
  • dir, чтобы указать, куда поместить временный файл.
  • os.path.split, чтобы отделить каталог от имени файла.

import tempfile
import os
dirname, basename = os.path.split(filename)
temp = tempfile.NamedTemporaryFile(prefix=basename, dir=dirname)
print(temp.name)
person unutbu    schedule 05.01.2012
comment
Если имя файла = 'foo', тогда имя каталога будет ''. Я приятно удивлен, что NamedTemporaryFile работает с dir='' так же, как и с dir=None. Спасибо! - person TomOnTime; 06.01.2012
comment
Просто чтобы сделать это явным: вы также должны передать delete=False конструктору NamedTemporaryFile, иначе файл будет удален при закрытии. - person moeffju; 02.04.2013

Вы можете передать местоположение файла в параметре конструктора 'dir'. Работает, как хочешь.

>>> t = tempfile.NamedTemporaryFile(dir="/Users/rafal")
>>> t.name
'/Users/rafal/tmplo45Js'

Источник: http://docs.python.org/library/tempfile.html#tempfile.NamedTemporaryFile

person Rafał Rawicki    schedule 05.01.2012
comment
информация: без delete=False файл удаляется, как только закрывается обработчик файла. - person gecco; 05.01.2012
comment
Это предполагает, что мы знаем, что такое директор. - person TomOnTime; 06.01.2012
comment
Мы знаем это. Вопрос OP уже содержит разбиение пути на каталог и имя файла, поэтому писать об этом здесь излишне. - person Rafał Rawicki; 06.01.2012

Чтобы соответствовать всему вашему контрольному списку, я думаю, вы бы хотели использовать...

temp = tempfile.NamedTemporaryFile(prefix=data_file_name, dir=path,
                                   delete=False)

Важно иметь delete=False, иначе:

[...] Если для удаления установлено значение true (по умолчанию), файл удаляется, как только он закрывается.

person Ricardo Cárdenes    schedule 05.01.2012
comment
Это предполагает, что мы знаем, что такое путь. - person TomOnTime; 06.01.2012

Я использую текущее время как «некоторые случайные данные», добавленные к базовой строке для уникального временного имени файла:

import time

temp_file_name = data_file_name + str(time.time()) 
person David Pointer    schedule 05.01.2012
comment
Это заманчиво, но я видел достаточно проблем с безопасностью от людей, внедряющих свою собственную временную файловую систему, которые, как я знаю, используют ту, которую предоставляет tempfile. - person TomOnTime; 06.01.2012
comment
Как добавленное примечание, несколько лет спустя у этого будут конфликты, если он будет выполняться дважды в одну и ту же миллисекунду, что определенно возможно в случаях использования большинства людей. Лучше просто использовать официальную реализацию tempfile и тому подобное, и условия гонки, когда вы пытаетесь этого избежать. - person daboross; 23.07.2014

Используемый вами модуль tempfile обеспечивает безопасный способ управления временными файлами. Если вы действительно хотите использовать свою собственную систему, вы должны просто знать, что она может быть уязвима для атак (особенно атак по символическим ссылкам).

Простой способ создать временное уникальное имя файла (хотя и довольно длинное):

import uuid
import os

tempfilename = 'myprefix-%s.dat' % str(uuid.uuid4())

with open(tempfilename, 'rw') as tempfile:
    # do stuff

os.remove(tempfilename)

Но это немного хакерски; на самом деле лучше рассмотреть возможность использования модуля tempfile с правильными параметрами prefix и dir, переданными в NamedTemporaryFile, как описано в других ответах.

person G-J    schedule 05.01.2012
comment
Это заманчиво, но я видел достаточно проблем с безопасностью, вызванных тем, что люди запускают свою собственную временную файловую систему, и я знаю, что они используют ту, которую предоставляет tempfile. - person TomOnTime; 06.01.2012
comment
Безусловно, использование чего-то подобного в рабочем коде — плохая идея. В среде, где это не проблема (например, регистрация данных моделирования), uuid представляет собой способ создания уникальной случайной строки. - person G-J; 07.01.2012