Как передать gzip, созданный на лету, в Python?

Я хотел бы передать большой файл журнала по сети с помощью asyncio. Я извлекаю данные из базы данных, форматирую их, сжимаю с помощью Python zlib и передаю по сети.

Вот в основном код, который я использую:

@asyncio.coroutine
def logs(requests):
    # ...

    yield from resp.prepare(request)

    # gzip magic number and compression format
    resp.write(b'\x1f\x8b\x08\x00\x00\x00\x00\x00')
    compressor = compressobj()
    for row in rows:
        ip, uid, date, url, answer, volume = row
        NCSA_ROW = '{} {} - [{}] "GET {} HTTP/1.0" {} {}\n'
        row = NCSA_ROW.format(ip, uid, date, url, answer, volume)
        row = row.encode('utf-8')
        data = compressor.compress(row)
        resp.write(data)
    resp.write(compressor.flush())
    return resp

Файл, который я получаю, не может быть открыт с помощью gunzip, и zcat вызывает следующую ошибку:

gzip: out.gz: unexpected end of file

person amirouche    schedule 21.06.2016    source источник


Ответы (1)


Ваш заголовок gzip неверен (8 байтов вместо 10), и вы следуете за ним с потоком zlib, который использует другой заголовок и трейлер. Даже если бы у вас был правильный заголовок gzip и если бы у вас был необработанный поток deflate вместо потока gzip, вы все равно не написали бы трейлер gzip.

Чтобы сделать это правильно, не пытайтесь написать свой собственный заголовок gzip. Вместо этого попросите zlib записать полный поток gzip, который запишет правильный заголовок, сжатые данные и трейлер. Вы можете сделать это, предоставив wbits значение от 31 до compressobj().

person Mark Adler    schedule 21.06.2016