Команда shutil copy записывает 0-байтовые файлы, копируя временные файлы - PullRequest
1 голос
/ 19 марта 2019

У меня есть другой метод, вызывающий эту функцию 3 раза для записи 3 разных файлов.Первые 2 файла копируются в целевую папку, как и ожидалось, третий файл всегда равен нулю байтов.Если я отключаю удаление, я вижу, что все 3 временных файла успешно записаны.Код не сообщает об ошибках, но в конце процесса третий файл всегда пуст.

Кто-нибудь знает, почему это происходит с ошибкой 1 из 3 раз?

def write_file(file_destination: str, content: bytes):
    with tempfile.NamedTemporaryFile() as fp:
        fp.write(content)
        shutil.copy(fp.name, file_destination)

Следующий вариант работает, однако я хотел бы понять, почему первые два файла работают, а третий - нет в приведенном выше коде.

def write_file(file_destination: str, content: bytes):
    with tempfile.NamedTemporaryFile(delete=False) as fp:
        fp.write(content)
    shutil.copy(fp.name, file_destination)
    os.remove(fp.name)

1 Ответ

2 голосов
/ 19 марта 2019

Это потому, что content еще не записано на диск, когда вы выполняете копирование. Это происходит потому, что записи буферизуются и не всегда происходят сразу после вызова file.write. Чтобы убедиться, что содержимое записано на диск в данный момент, вы можете использовать file.flush.

В вашем случае достаточно изменить код на:

def write_file(file_destination: str, content: bytes):
    with tempfile.NamedTemporaryFile() as fp:
        fp.write(content)
        fp.flush()
        shutil.copy(fp.name, file_destination)

Для получения дополнительной информации о том, когда содержимое фактически записывается на диск, вы можете ознакомиться с документацией io.BufferedWriter. Соответствующая часть:

Буфер будет записан в базовый объект RawIOBase при различных условиях, в том числе:

  • когда буфер становится слишком маленьким для всех ожидающих данных;
  • когда вызывается flush ();
  • при запросе seek () (для объектов BufferedRandom);
  • когда объект BufferedWriter закрыт или уничтожен.

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

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

...