Как читать строку Gzip без заголовка или mimetype? Использование Python - PullRequest
2 голосов
/ 04 февраля 2012

У меня есть сжатая строка, она создается из другого приложения. Теперь, когда у меня есть строка (без mimetype или заголовков), мне нужно ее распаковать.

Есть ли способ сделать это в Python?

[РЕДАКТИРОВАТЬ] Для проверки я буквально скопировал, затем вставил строку в блокнот и затем переименовал в .gz Я также проверил, вставив саму строку в IDLE

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

Использование zlib.decompress(mystring) дает ошибку Error -3 while decompressing data: incorrect header check

1 Ответ

1 голос
/ 05 февраля 2012

Подтверждение комментариев @reclosedev и добавление еще:

Байты после ] должны быть декодированы base64.

В результате этого имеется 4 байта, составляющих длину распакованных данных в виде 32-разрядного двоичного числа с прямым порядком байтов. Остальная часть - это gzip-поток, соответствующий RFC-1952, который можно узнать, начиная с 1F 8B 08. Результаты распаковки выглядят как двоичные данные, а не как строки ASCII 1 и 0.

Код:

lines = [
    # extracted from the linked csv file 
    "[133,120,696,286]MmEAAB+LCAAAAAAABADtvQdg [BIG snip] a0bokyYQAA",
    "[73,65,564,263]bkgAAB+LCAAAAAAABADtvQdgHE [BIG snip] kgAAA==",
    ]
import zlib, struct
for line in lines:
    print
    b64 = line.split(']')[1]
    raw = b64.decode('base64')
    print "unknown:", repr(raw[:4])
    print "unknown as 32-bit LE int:", struct.unpack("<I", raw[:4])[0]
    ungz = zlib.decompress(raw[4:], 31)
    print len(ungz), "bytes in decompressed data"
    print "first 100:", repr(ungz[:100])

Выход:

unknown: '2a\x00\x00'
unknown as 32-bit LE int: 24882
24882 bytes in decompressed data
first 100: '\xff\xe0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xf0\x00\x00\x00\x00\x00\x00\x00
\x00\x00\x00'

unknown: 'nH\x00\x00'
unknown as 32-bit LE int: 18542
18542 bytes in decompressed data
first 100: '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x7f\xff\xff\xff\xff
\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
\x00\x00\x00\x00\x07\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x80
\x00\x00\x00'

Обновление в ответ на комментарий

Чтобы получить 1 и 0, которые мне нужны, я просто добавил это к приведенному выше cleaned = bin (int (binascii.hexlify (ungz), 16))

"Просто"? Вам нужно будет снять '0b' спереди, а затем дополнить фронт таким количеством начальных нулей, сколько необходимо, чтобы длина была кратна 8. Например, с лучшим методом:

>>> import binascii
>>> ungz = '\x01\x80'
>>> bin(int(binascii.hexlify(ungz), 16))
'0b110000000'
>>> ''.join('{0:08b}'.format(ord(x)) for x in ungz)
'0000000110000000'

Вы тщательно проверили, чтобы убедиться, что вы действительно хотите '0000000110000000', а не '1000000000000001'?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...