Расшифровать Base64 Gzip в питоне
Я пытаюсь декодировать файл активности gzip garmin, используя Python. По словам Гармина, файл является файлом base64 gz. Я загружаю файл из браузера по почте и получаю данные в приложении Django.
Начало файла выглядит следующим образом.
begin-base64 644 data.xml.gz \ nH4sIAAAAAAAAA y9a4 lx3Hn d6fguB7JzNuGZkNigNfdrAGbMAYaXeNfbPolXplYiRSIFu
Я использовал следующий код для настройки для дополнения и декодирования base64:
import base64
padding_factor = (4 - len(data) % 4) % 4
data += "="*padding_factor
data_decoded = base64.b64decode(unicode(data).translate(dict(zip(map(ord, u'-_'), u'+/'))))
Начало data_decoded выглядит на экране следующим образом:
\ X Е8"\x9f\ XE6\ XDA \ XB1 \ Xee \ XB8\xeb\x8e\x1dj\xd6\ XB1\x9aX3\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\x03/Z\ XE2\ ш \x1ewz~\x0b\x81\ XEC \ x9c \ XCD \xb8fd6(\ г}\ XDA \xc0\x19\xb3\x00a\xa5\xde5\ XF6\ XCF \xa2U\xE9\x95\x88\x91H\x81n\ XCB \xf7\ XB4\x9f\ XCC \xa7y%\ XBD \x95\x9e\x13\ XCD \x10\xf9Th\x04\x8d\ XDF \ XDF \xa6\ Xba \ xA9 \ XCD \xf9=s\xf8G\ хк
print data_decoded
выглядит так:
}??? а??5?ϢU镈?H? П???? Y%????? че??ߦ????= с?G?
Затем я пытаюсь распаковать файл, используя следующее:
from cStringIO import StringIO
from gzip import GzipFile
sio = StringIO(data_decoded)
gzf = gzip.GzipFile(fileobj=sio)
guff = gzf.read()
После чего я получаю следующую ошибку:
File "<stdin>", line 1, in <module>
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/gzip.py", line 245, in read
self._read(readsize)
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/gzip.py", line 287, in _read
self._read_gzip_header()
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/gzip.py", line 181, in _read_gzip_header
raise IOError, 'Not a gzipped file'
IOError: Not a gzipped file
Я также попытался сохранить файл непосредственно на диск и запустить gunzip из командной строки, что также приводит к той же ошибке.
Любая помощь приветствуется.
2 ответа
Похоже, вы расшифровываете все это, включая begin-base64 644 data.xml.gz
часть, так что вы получаете кучу мусора в начале:
b1 = '''begin-base64 644 data.xml.gz\nH4sIAAAAAAAAA y9a4 lx3Hn
d6fguB7JzNuGZkNigNfdrAGbMAYaXeNfbPolXplYiRSIFu'''
b2 = '''\nH4sIAAAAAAAAA y9a4 lx3Hn
d6fguB7JzNuGZkNigNfdrAGbMAYaXeNfbPolXplYiRSIFu'''
Если вы запустите свой алгоритм на b2, вы получите что-то, начиная с этого:
m\xe8"\x9d\xb6\xac{\xae
(Я не знаю, как ты потерял m
в копировании и вставке, но в любом случае, это недействительно.)
Если вы запустите его на b2
, вы получите что-то, начиная с этого:
\x1f\x8b\x08\x00\x00\x00
Это то, что ты хочешь.
Конечно снимая '\n'
имеет тот же эффект, так как base64 игнорирует пробелы. Так что, скорее всего, он используется в качестве разделителя. Если это на самом деле '\\n'
(ака r'\n'
) скорее чем '\n'
Вы должны удалить его, чтобы получить правильный ответ.
Кроме того, вы, кажется, делаете много дополнительной работы без уважительной причины. Скорее всего, данные на самом деле правильно дополнены, но эта часть может быть полезной. Но в целом translate(dict(zip(map(ord, u'-_'), u'+/')))
делает то же самое, что и прохождение altchars
аргумент b64decode
, но менее эффективно и труднее читать (если это правильно). (Кстати, если бы вы делали translate
как оптимизация против стоимости звонка replace
дважды преобразование в Unicode и обратно почти наверняка сокрушит экономию. Даже если вы определили и определили, что это имеет значение, вы, вероятно, захотите сгенерировать translate
Карта выше - и для эффективности, так что вы не делаете это один раз для строки, и, что более важно, для удобочитаемости.)
Собираем это вместе:
data = '''begin-base64 644 data.xml.gz\nH4sIAAAAAAAAA y9a4 lx3Hn
d6fguB7JzNuGZkNigNfdrAGbMAYaXeNfbPolXplYiRSIFu'''
_, data = data.split('\n', 1)
padding_factor = (4 - len(data) % 4) % 4
data += "="*padding_factor
data_decoded = base64.b64decode(data, '-_')
Опять же, если у вас есть '\\n'
а не '\n'
, изменить split
линия соответственно.
Вам нужно удалить начало файла, так как он не является частью данных base64. Если вы знаете, что \n
будет частью каждого файла, который вы можете использовать в качестве разделителя:
index = data.find('\\n')
if index > 0:
data = data[index+2:]