我正在尝试使用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,这也会导致相同的错误。
非常感谢任何帮助。
答案 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
行。