2010-06-09 66 views
4

出于某种原因,我无法让cPickle.load在ZipFile.open()返回的文件类型对象上工作。 如果我对由ZipFile.open()返回的文件类型对象调用read(),我可以使用cPickle.loads。从zip文件加载pickle文件

例....

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() 

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

+0

你试过'import picklefork'吗? :P – FrustratedWithFormsDesigner 2010-06-09 14:27:05

+3

试着告诉我们在这种情况下什么“不起作用”我们没有水晶球。 – 2010-06-09 14:37:02

+0

@John,复制和过去他给出的代码有多难?它在最后一个片段中得到一个'EOFError'。 – 2010-06-09 14:39:15

回答

7

这是由于zipfile模块(Python 2.6中引入的ZipFile类的.open方法)实现的pseudofile对象中的缺陷造成的。试想一下:

>>> 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的标准库中的这个bug在Python 2.7中修复 - 我要检查一下。

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

再次编辑:错误仍然存​​在在Python 2.6.5,Python 2.6中最新的bug修复版本 - 因此,如果您不能升级到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')) 
>>> 

这只是老这些混沌向后兼容“的协议0”(默认值),请正确使用伪文件对象行为当在load中混合读取和读取线程调用时(协议0也比较慢,并且导致更大的pickle,所以它绝对不推荐,除非与旧版本Python的向后兼容或者0产生的pickle的ascii-only特性是强制性的在你的应用程序中的约束)

+0

我在Python 2.6.6上使用协议1和2得到了相同的虚假EOFError。 – dvogel 2012-04-16 18:18:57