gzip в bash против python - PullRequest
       60

gzip в bash против python

0 голосов
/ 10 июля 2020

В Bash, когда вы gzip файл, оригинал не сохраняется, тогда как в Python вы можете использовать библиотеку gzip, как это (как показано здесь в «Примеры использования "section):

import gzip
import shutil
with open('/home/joe/file.txt', 'rb') as f_in:
    with gzip.open('/home/joe/file.txt.gz', 'wb') as f_out:
        shutil.copyfileobj(f_in, f_out)

По умолчанию сохраняется исходный файл. Я не мог найти способ не сохранить его при сжатии. Нужно ли мне ждать завершения работы с gzip, чтобы удалить файл?

Ответы [ 3 ]

2 голосов
/ 10 июля 2020

Если вы работаете в системе, подобной unix, вы можете отменить связь с файлом после открытия, чтобы он больше не находился в файловой системе. Но до тех пор, пока вы не закроете анонимный файл, он все равно займет место на диске.

import gzip
import shutil
import os
with open('deleteme', 'rb') as f_in:
    with gzip.open('deleteme.gz', 'wb') as f_out:
        os.unlink('deleteme') # *after* we knew the gzip open worked!
        shutil.copyfileobj(f_in, f_out)

Насколько мне известно, это не работает с Windows. Вам нужно выполнить удаление после завершения процесса архивирования. Вы можете изменить его имя на что-то вроде "thefile.temporary" или даже переместить его в другой каталог (быстро, если каталог в той же файловой системе, но скопировать, если он другой).

2 голосов
/ 10 июля 2020

Учитывая, что при запуске GZip (в Bash или где-либо еще в этом отношении):

  • GZip требует исходных данных для выполнения действия сжатия
  • GZip разработан для обработки данных в основном произвольного размера
  • Следовательно: GZip вряд ли создаст временный файл в памяти, скорее, он почти наверняка удалит оригинал после того, как gzip будет выполнен.

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

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

1 голос
/ 11 июля 2020

Код ниже (частично основанный на ответе 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)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...