使用Pickler时出现Python Pickle EOFError(但使用pickle.dump()时没有)

1 投票
2 回答
2109 浏览
提问于 2025-04-16 21:03

我在Windows 7上用Python的pickle功能想把一些对象保存到硬盘上。下面是我用的代码,但几乎任何随便的对象都保存失败(saveobj的内容不重要,反正都会失败)。以下是我的测试代码:

import pickle, os, time
outfile = "foo.pickle"
f = open(outfile, 'wb')
p = pickle.Pickler(f, -1)
saveobj = ( 2,3,4,5,["hat", {"mat": 6}])
p.save(saveobj)
#pickle.dump(saveobj, f)
print "done pickling"
f.close()
g  = open(outfile, 'rb')
tup = pickle.load(g)
g.close()
print tup

当我运行这段代码时,出现了以下输出/错误:

done pickling
Traceback (most recent call last):
  File "C:\Users\user\pickletest2.py", line 13, in <module>
    tup = pickle.load(g)
  File "C:\Python26\lib\pickle.py", line 1370, in load
    return Unpickler(file).load()
  File "C:\Python26\lib\pickle.py", line 858, in load
    dispatch[key](self)
  File "C:\Python26\lib\pickle.py", line 880, in load_eof
    raise EOFError
EOFError

不过,如果我用pickle.dump()而不是使用Pickler对象,代码就能正常工作了。我之所以想用Pickler,是因为我想对每个对象进行一些操作,然后再进行保存。

有没有人知道为什么我的代码会这样?我查了一下,发现没有使用'wb'和'rb'模式通常会导致这个问题,还有就是没有调用f.close(),但我这两者都有。使用-1作为协议会有问题吗?我想保留这个设置,因为它可以处理那些定义了__slots__方法但没有定义__getstate__方法的对象。

2 个回答

1

一般来说,使用cPickle会更好,因为它的性能更高(因为cPickle是用C语言写的)。不过,使用dump也能正常工作:

import pickle
import os, time
outfile = "foo.pickle"
f = open(outfile, 'wb')
p = pickle.Pickler(f, -1)
saveobj = ( 2,3,4,5,["hat", {"mat": 6}])
p.dump(saveobj)
#pickle.dump(saveobj, f)
f.close()
print "done pickling"
#f.close()
g  = open(outfile, 'rb')
u = pickle.Unpickler(g) #, -1)
tup = u.load()
#tup = pickle.load(g)
g.close()
print tup
2

Pickler.save() 是一个比较底层的方法,通常不建议直接调用它。

如果你用 p.dump(saveobj) 来代替 p.save(saveobj),它就会按预期工作。

也许应该把它叫做 _save,这样就不会让人困惑了。不过 dump 是文档中描述的方法,而且它和模块级别的 pickle.dump 很好地对应起来。

撰写回答