Python: Создание потоковой передачи gzip'd подобный файлу?

Я пытаюсь выяснить лучший способ сжать поток с Python zlib.

У меня есть подобный файлу входной поток (input, ниже) и функция вывода, которая принимает подобное файлу (output_function, ниже):

with open("file") as input:
    output_function(input)

И я хотел бы gzip-сжаться input блоки прежде, чем отправить их в output_function:

with open("file") as input:
    output_function(gzip_stream(input))

Похоже, что gzip модуль предполагает, что или вход или вывод будут gzip'd файлом на диске …, Таким образом, я предположу, что zlib модуль - то, что я хочу.

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

Конечно, я мог записать обертку вокруг zlib.Compress.compress и zlib.Compress.flush (Compress возвращается zlib.compressobj()), но я был бы взволнован по поводу понимания превратно буферных размеров или чего-то подобного.

Так, что самый простой путь состоит в том, чтобы создать потоковую передачу, gzip-сжав подобный файлу с Python?

Править: Для разъяснения входной поток и сжатый поток вывода являются оба слишком большими для умещений в памяти, таким образом, что-то как output_function(StringIO(zlib.compress(input.read()))) действительно не решает проблему.

22
задан David Wolever 3 February 2010 в 18:02
поделиться

3 ответа

Это довольно громоздко (самореклама и т.д. несколько минут на написание, ничего особенного), но он делает то, что вам нужно, если вы все еще заинтересованы в использовании gzip вместо zlib напрямую.

По сути, GzipWrap - это (очень ограниченный) файловый объект, который создает сжатый файл из заданного итеративного объекта (например, файлового объекта, списка строк, любого генератора .. .)

Конечно, он производит двоичный файл, поэтому не было смысла реализовывать "readline".

У вас должна быть возможность расширить его для охвата других случаев или для использования в качестве самого итеративного объекта.

from gzip import GzipFile

class GzipWrap(object):
    # input is a filelike object that feeds the input
    def __init__(self, input, filename = None):
        self.input = input
        self.buffer = ''
        self.zipper = GzipFile(filename, mode = 'wb', fileobj = self)

    def read(self, size=-1):
        if (size < 0) or len(self.buffer) < size:
            for s in self.input:
                self.zipper.write(s)
                if size > 0 and len(self.buffer) >= size:
                    self.zipper.flush()
                    break
            else:
                self.zipper.close()
            if size < 0:
                ret = self.buffer
                self.buffer = ''
        else:
            ret, self.buffer = self.buffer[:size], self.buffer[size:]
        return ret

    def flush(self):
        pass

    def write(self, data):
        self.buffer += data

    def close(self):
        self.input.close()
11
ответ дан 29 November 2019 в 05:31
поделиться

Модуль gzip поддерживает сжатие до файлового объекта, передает параметр fileobj в GzipFile, а также имя файла. Имя файла, которое вы передаете, не обязательно должно существовать, но в заголовке gzip есть поле имени файла, которое необходимо заполнить.

Обновление

Этот ответ не работает. Пример:

# tmp/try-gzip.py 
import sys
import gzip

fd=gzip.GzipFile(fileobj=sys.stdin)
sys.stdout.write(fd.read())

вывод:

===> cat .bash_history  | python tmp/try-gzip.py  > tmp/history.gzip
Traceback (most recent call last):
  File "tmp/try-gzip.py", line 7, in <module>
    sys.stdout.write(fd.read())
  File "/usr/lib/python2.7/gzip.py", line 254, in read
    self._read(readsize)
  File "/usr/lib/python2.7/gzip.py", line 288, in _read
    pos = self.fileobj.tell()   # Save current position
IOError: [Errno 29] Illegal seek
4
ответ дан 29 November 2019 в 05:31
поделиться

Используйте модуль cStringIO (или StringIO) в сочетании с zlib:

>>> import zlib
>>> from cStringIO import StringIO
>>> s.write(zlib.compress("I'm a lumberjack"))
>>> s.seek(0)
>>> zlib.decompress(s.read())
"I'm a lumberjack"
2
ответ дан 29 November 2019 в 05:31
поделиться
Другие вопросы по тегам:

Похожие вопросы: