2015-03-31 5 views
2

Есть ли способ сделать потоковое декомпрессии однофайловых архивов?Потоковая декомпрессия zip-архивов в python

В настоящее время в s3 я имею произвольно большие архивы с заархивированными файлами (один файл в архиве). Я хотел бы иметь возможность обрабатывать файлы, итерации по ним без фактической загрузки файлов на диск или в память.

Простой пример:

import boto 

def count_newlines(bucket_name, key_name): 
    conn = boto.connect_s3() 
    b = conn.get_bucket(bucket_name) 
    # key is a .zip file 
    key = b.get_key(key_name) 

    count = 0 
    for chunk in key: 
     # How should decompress happen? 
     count += decompress(chunk).count('\n') 

    return count 

This answer демонстрирует способ делать то же самое с файлами упакованных gzip. К сожалению, мне не удалось получить тот же метод для работы с использованием модуля zipfile, так как для него требуется случайный доступ к распакованному файлу.

+0

Вы пытались адаптировать этот код, чтобы использовать [ 'zipfile'] (https://docs.python.org/2/library/zipfile.html) вместо' zlib'? – MattDMo

+0

Да! ZipFile ожидает случайный доступ к файлу, который он распаковывает, поэтому я не думаю, что он действительно будет работать с итератором s3. –

+1

См. Также https://stackoverflow.com/questions/10405210/create-and-stream-a- large-archive-without-storing-it-in-memory-or-on-disk – DNA

ответ

0

Почтовый заголовок находится в конце файла, поэтому ему нужен произвольный доступ. См. https://en.wikipedia.org/wiki/Zip_(file_format)#Structure.

Вы можете разобрать локальный заголовок файла, который должен быть в начале файла для простой молнии, и распаковывать байты с zlib (см zipfile.py). Это недействительный способ чтения zip-файла, и, хотя он может работать для вашего конкретного сценария, он также может потерпеть неудачу на множестве действительных почтовых индексов. Чтение заголовка центрального каталога является единственным правильным способом чтения zip.

0

Да, но вам, вероятно, придется написать свой собственный код, чтобы сделать это, если он должен быть в Python. Вы можете посмотреть на sunzip для примера на языке C, чтобы распаковать zip-файл из потока. sunzip создает временные файлы, поскольку он распаковывает записи zip, а затем перемещает эти файлы и соответствующим образом задает их атрибуты после чтения центрального каталога в конце. Претензии, что вы должны иметь возможность искать в центральном каталоге, чтобы правильно распаковать zip-файл, неверны.

0

Вы можете сделать это в Python 3.4.3, используя ZipFile следующим образом:

with ZipFile('spam.zip') as myzip: 
    with myzip.open('eggs.txt') as myfile: 
     print(myfile.read()) 

Python Docs

1

Вы можете использовать https://pypi.python.org/pypi/tubing, он даже имеет встроенную поддержку источника s3 с использованием boto3.

from tubing.ext import s3 
from tubing import pipes, sinks 
output = s3.S3Source(bucket, key) \ 
    | pipes.Gunzip() \ 
    | pipes.Split(on=b'\n') \ 
    | sinks.Objects() 
print len(output) 

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

class CountWriter(object): 
    def __init__(self): 
     self.count = 0 
    def write(self, chunk): 
     self.count += len(chunk) 
Counter = sinks.MakeSink(CountWriter) 
Смежные вопросы