0

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

文件的开头如下所示。

begin-base64 644 data.xml.gz\nH4sIAAAAAAAAAA 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看起来像这样:

}???a??5?ϢU镈?H?n????̧y%?????Th????????=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 ,这也会导致相同的错误。

任何帮助将非常感激。

4

2 回答 2

0

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

index = data.find('\\n')
if index > 0:
    data = data[index+2:]
于 2012-12-17T21:17:56.760 回答
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 会忽略空格。所以最有可能的是,它被用作分隔符。如果这实际上是 a '\\n'(aka r'\n') 而不是 a '\n'则必须将其删除才能获得正确答案。

此外,您似乎无缘无故地做了很多额外的工作。很可能数据实际上已正确填充,但那部分可能是值得的。但整体与将参数translate(dict(zip(map(ord, u'-_'), u'+/')))传递给 做同样的事情,但效率较低且更难阅读(如果它是正确的)。(顺便说一句,如果您是针对两次调用的成本进行优化,那么与 Unicode 之间的转换几乎肯定会超过节省的成本。即使您已经分析并确定它有所作为,您可能会想要生成上面的映射——既是为了提高效率,所以你不要为每个字符串做一次,更重要的是,为了可读性。)altcharsb64decodetranslatereplacetranslate

把它放在一起:

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, '-_')

同样,如果您有 a'\\n'而不是 a '\n',请相应地更改该split行。

于 2012-12-17T21:19:55.047 回答