6

由于某种原因,我无法让 cPickle.load 处理 ZipFile.open() 返回的文件类型对象。如果我在 ZipFile.open() 返回的文件类型对象上调用 read(),我可以使用 cPickle.loads。

例子 ....

import zipfile
import cPickle

# the data we want to store
some_data = {1: 'one', 2: 'two', 3: 'three'}

#
# create a zipped pickle file
#
zf = zipfile.ZipFile('zipped_pickle.zip', 'w', zipfile.ZIP_DEFLATED)
zf.writestr('data.pkl', cPickle.dumps(some_data))
zf.close()

#
# cPickle.loads works
#
zf = zipfile.ZipFile('zipped_pickle.zip', 'r')
sd1 = cPickle.loads(zf.open('data.pkl').read())
zf.close()

#
# cPickle.load doesn't work
#
zf = zipfile.ZipFile('zipped_pickle.zip', 'r')
sd2 = cPickle.load(zf.open('data.pkl'))
zf.close()

注意:我不想只压缩泡菜文件,而是压缩许多其他类型的文件。这只是一个例子。

4

1 回答 1

8

这是由于zipfile模块实现的伪文件对象存在缺陷(对于Python 2.6 中引入.open的类的方法)。ZipFile考虑:

>>> f = zf.open('data.pkl')
>>> f.read(1)
'('
>>> f.readline()
'dp1\n'
>>> f.read(1)
''
>>> 

.read(1)--的序列.readline().loads内部所做的(在协议 0 泡菜上,Python 2 中的默认值,这是您在此处使用的)。不幸zipfile的是,不完美意味着这个特定的序列不起作用,在第一个读取/读取行对之后立即产生一个虚假的“文件结尾”(.read 返回一个空字符串)。

不确定 Python 标准库中的这个错误是否在 Python 2.7 中得到修复——我要检查一下。

编辑:刚刚检查过——该错误已在 Python 2.7 rc1(当前最新的 2.7 版本的候选发布版)中修复。我还不知道它是否也在 2.6 的最新错误修复版本中得到修复。

再次编辑:该错误仍然存​​在于 Python 2.6.5(Python 2.6 的最新错误修复版本)中——因此,如果您无法升级到 2.7 并且需要来自 的表现更好的伪文件对象ZipFile.open,则似乎是 2.7 修复的反向移植唯一可行的解​​决方案。

请注意,不确定您是否需要表现更好的伪文件对象;如果您控制转储调用并且可以使用最新最好的协议,那么一切都会好起来的:

>>> zf = zipfile.ZipFile('zipped_pickle.zip', 'w', zipfile.ZIP_DEFLATED)
>>> zf.writestr('data.pkl', cPickle.dumps(some_data, -1))
>>> sd2 = cPickle.load(zf.open('data.pkl'))
>>> 

只有旧的向后兼容的“protocol 0”(默认)在混合 read 和 readline 调用时需要适当的伪文件对象行为load(protocol 0 也较慢,并且会导致更大的泡菜,因此除非向后兼容,否则绝对不推荐对于旧的 Python 版本,或者 0 产生的 pickle 的纯 ascii 特性,是应用程序中的强制性约束)。

于 2010-06-09T15:04:47.163 回答