Код ниже (частично основанный на ответе tdelaney) будет делать следующее:
- читать файл, сжимать на лету и сохранять все сжатые данные в памяти
- удалить входной файл
- затем записать сжатые данные
Это для случая использования, когда у вас есть полная файловая система, которая не позволяет вам записывать сжатые данные одновременно что несжатый файл существует на диске. Поэтому, чтобы обойти эту проблему, необходимо хранить все данные в памяти (если у вас нет доступа к внешнему хранилищу), но для минимизации этой стоимости памяти, насколько это возможно, только сжатые данные полностью хранятся в памяти, в то время как несжатые данные читаются по частям.
Конечно, существует риск потери данных, если программа прерывается между удалением входного файла и завершением записи сжатых данных на диск.
Существует также вероятность сбоя, если недостаточно памяти, но входной файл не будет удален в этом случае, потому что MemoryError
будет поднято до того, как будет достигнуто os.unlink
.
Стоит отметить, что это не конкретно отвечает на вопрос, о котором идет речь, а именно, удаление входного файла при продолжении чтения из него. Это возможно в unix -подобных операционных системах, но это не дает практических преимуществ по сравнению с обычным поведением командной строки gzip
, потому что освобождение дискового пространства не происходит до тех пор, пока файл не будет закрыт, поэтому это приносит в жертву возможность восстановления. в случае сбоя, без получения дополнительного места для манипулирования данными в обмен на эту жертву. (Для сосуществования несжатых и сжатых данных необходимо по-прежнему .)
import gzip
import shutil
import os
from io import BytesIO
filename = 'deleteme'
buf = BytesIO()
# compress into memory - don't store all the uncompressed data in memory
# but do store all the compressed data in memory
with open(filename, 'rb') as fin:
with gzip.open(buf, 'wb') as zbuf:
shutil.copyfileobj(fin, zbuf)
# sanity check for already compressed data
length = buf.tell()
if length > os.path.getsize(filename):
raise RuntimeError("data *grew* in size - refusing to delete input")
# delete input file and then write out the compressed data
buf.seek(0)
os.unlink(filename)
with open(filename + '.gz', 'wb') as fout:
shutil.copyfileobj(buf, fout)