在python中解码Base64 Gzip

时间:2012-12-17 19:17:27

标签: python base64 gunzip garmin

我正在尝试使用Python解码gzip garmin活动文件。据Garmin说,该文件是base64 gz文件。我通过post从浏览器上传文件并在Django App中接收数据。

文件的开头看起来像这样。

  

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的开头在屏幕上显示如下:

  

\ xe8" \ x9f \ XE6 \ XDA \ XB1 \ XEE \ XB8 \ XEB \ x8e \ x1dj \ XD6 \ XB1 \ x9aX3 \ X1F \ x8b \ X08 \ X00 \ X00 \ X00 \ X00 \ X00 \ X00 \ X03 / Z \ XE2 \ W \ x1ewz〜\ X0B \ X81 \ XEC \ x9c \ XCD \ xb8fd6(\ R} \ 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 \ XFC

print data_decoded看起来像这样:

  

} ...的ΔΣ5?ϢU镈3 H 3 N ???? Y%?????钍??ߦ???? = S·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 个答案:

答案 0 :(得分:0)

您需要剥离文件的开头,因为它不是base64数据的一部分。如果您知道\n将成为每个文件的一部分,您可以将其用作分隔符:

index = data.find('\\n')
if index > 0:
    data = data[index+2:]

答案 1 :(得分:0)

看起来你正在解码整个事情,包括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和从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行。