2010-06-09 68 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