#python #temporary-files
Вопрос:
Я пытаюсь создать несколько временных файлов и выполнить некоторые операции над ними внутри цикла. Затем я получу доступ к информации обо всех временных файлах. И выполните некоторые операции с этой информацией. Для простоты я привел следующий код, который воспроизводит мою проблему:
import tempfile
tmp_files = []
for i in range(40):
tmp = tempfile.NamedTemporaryFile(suffix=".txt")
with open(tmp.name, "w") as f:
f.write(str(i))
tmp_files.append(tmp.name)
string = ""
for tmp_file in tmp_files:
with open(tmp_file, "r") as f:
data = f.read()
string = data
print(string)
ОШИБКА:
with open(tmp_file, "r") as f: FileNotFoundError: [Errno 2] No such file or directory: '/tmp/tmpynh0kbnw.txt'
Когда я просматриваю каталог /tmp (с некоторым time.sleep(2) в цикле) Я вижу, что файл удален и сохранен только один. И для этого ошибка.
Конечно, я мог бы сохранить все файлы с этим флагом tempfile.NamedTemporaryFile(suffix=".txt", delete=False)
. Но это не идея. Я хотел бы сохранить временные файлы только на время выполнения скрипта. Я также мог бы удалить файлы с помощью os.remove. Но мой вопрос в том, почему это происходит. Потому что я ожидал, что файлы будут храниться до конца выполнения. Потому что я не закрываю файл при выполнении (или я?).
Заранее большое спасибо.
Комментарии:
1. Когда
with open...
блок заканчивается, файл автоматически закрывается.2. Но если
with open
оператор закрывает файл, как работает этот код? « a = tempfile. NamedTemporaryFile() с открытым(a.name , «w») как f: f.напишите («Hello») b = tempfile. NamedTemporaryFile() с открытым(b.name , «w») как f: f.напишите («Мир!») string = «» с открытым (a.name , «r») как f: строка = f.read() с открытым(b.name , «r») как f: строка = f.read() print(строка) «
Ответ №1:
tdelaney уже отвечает на ваш актуальный вопрос.
Я просто хотел бы предложить вам альтернативу NamedTemporaryFile
. Почему бы не создать временную папку, которая будет удалена (со всеми файлами в ней) в конце скрипта?
Вместо использования a NamedTemporaryFile
вы могли бы использовать tempfile.TemporaryDirectory
. Каталог будет удален при закрытии.
В приведенном ниже примере используется with
оператор, который автоматически закрывает дескриптор файла при завершении блока (см. Комментарий Джона Гордона).
import os
import tempfile
with tempfile.TemporaryDirectory() as temp_folder:
tmp_files = []
for i in range(40):
tmp_file = os.path.join(temp_folder, f"{i}.txt")
with open(tmp_file, "w") as f:
f.write(str(i))
tmp_files.append(tmp_file)
string = ""
for tmp_file in tmp_files:
with open(tmp_file, "r") as f:
data = f.read()
string = data
print(string)
Комментарии:
1. Это действительно помогает мне. Также я вижу, что это возможно без
with
statment. Просто:tmp_folder = tempfile.TemporaryDirectory()
, а затем простоtmp_file = os.path.join(temp_folder.name, f"{i}.txt")
. И таким образом вы могли бы сохранить временный каталог для дальнейшего использования в коде, безwith
необходимости . Но это просто другая альтернатива.
Ответ №2:
По умолчанию a NamedTemporaryFile
удаляет свой файл при закрытии. это немного сложно, но tmp = tempfile.NamedTemporaryFile(suffix=".txt")
в цикле приводит к удалению предыдущего файла при tmp
переназначении. Одним из вариантов является использование delete=False
параметра. Или просто оставьте файл открытым и seek
в начале после записи.
NamedTemporaryFile
это уже файловый объект — вы можете записывать в него напрямую, не открывая повторно. Просто убедитесь, что установлен режим «запись плюс» и в текстовом, а не в двоичном режиме. Поместите код в блок try / finally, чтобы убедиться, что файлы действительно удалены в конце.
import tempfile
tmp_files = []
try:
for i in range(40):
tmp = tempfile.NamedTemporaryFile(suffix=".txt", mode="w ")
tmp.write(str(i))
tmp.seek(0)
tmp_files.append(tmp)
string = ""
for tmp_file in tmp_files:
data = tmp_file.read()
string = data
finally:
for tmp_file in tmp_files:
tmp_file.close()
print(string)
Комментарии:
1. Большое вам спасибо за ваш ответ, он мне очень помогает! Но чрезмерное упрощение моей проблемы в примере, который я привел, скрывает некоторые другие элементы в моем коде. Но на самом деле, ваш ответ — это то, что я точно задаю в своем вопросе. Однако ответ @Thomas больше подходит для моей общей проблемы (не представлен в вопросе) и, конечно же, отвечает также на вопрос, который я задал.