Нежелательное удаление временных файлов

#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 больше подходит для моей общей проблемы (не представлен в вопросе) и, конечно же, отвечает также на вопрос, который я задал.