假设由于崩溃,我将pickle对象写入磁盘的尝试不完整。尝试取消对象总是会导致异常,或者写出的片段是否可能被解释为有效的pickle并且错误会被忽视?
答案 0 :(得分:7)
与提供的其他答案相反,我相信我们可以对泡菜的可恢复性做出强有力的论证。答案是:“是的,一个不完整的泡菜总是导致异常。”
为什么我们能够这样做?因为“pickle”格式实际上是一种基于堆栈的小语言。在基于堆栈的语言中,您编写的代码会在堆栈上逐项推送项目,然后调用对您已累积的数据执行某些操作的运算符。事实上,一个泡菜必须以命令“。”结束,它说:“现在将物品放在堆栈的底部并将其作为这个泡菜的值返回。”如果您的泡菜提前被切断,它将不会以此命令结束,您将收到EOF错误。
如果你想尝试恢复一些数据,你可能不得不编写自己的解释器,或者调用pickle.py来解决堆栈时想要引发EOFError而不会找到“。”。要记住的主要事情是,与大多数基于堆栈的语言一样,大数据结构是“向后”构建的:首先在堆栈中放置大量的小字符串或数字,然后调用一个操作,说“将它们放在一个列表中”或“抓住堆栈中的项目对并制作字典”。所以,如果一个pickle被打断了,你会发现堆栈中充满了将要构建的对象的部分,但是你会发现最终的代码告诉你 将会是什么从碎片中建造。
答案 1 :(得分:2)
腌制对象会返回一个str对象,或者将一个str对象写入一个文件......它不会修改原始对象。如果在一个酸洗调用中发生“崩溃”(异常),结果将不会返回给调用者,因此您没有任何可以尝试取消调用的内容。此外,你为什么要在异常后解开剩下的一些垃圾?
答案 2 :(得分:2)
这是S. Lott的答案的发展,我的建议是:在您的数据上附加哈希值或校验和,然后在再次取消镜像之前检查。
这是safepickle / safeunpickle的一个(简单)实现,用于说明如何使用哈希填充pickle数据(在这种情况下是加密强哈希):
import hashlib
import cPickle as pickle
_HASHLEN = 20
def safepickle(obj):
s = pickle.dumps(obj)
s += hashlib.sha1(s).digest()
return s
def safeunpickle(pstr):
data, checksum = pstr[:-_HASHLEN], pstr[-_HASHLEN:]
if hashlib.sha1(data).digest() != checksum:
raise ValueError("Pickle hash does not match!")
return pickle.loads(data)
l = range(20)
p = safepickle(l)
new_l = safeunpickle(p)
print new_l == l
这种方法是为了确保你的unpickle与之前腌制和写入磁盘的内容相匹配,但它当然不能防止混合不同的泡菜或恶意攻击。
(对于任何整个文件数据,此方法可以推广到模式safe_write_file
和safe_read_file
。)
答案 3 :(得分:1)
我怀疑你是否可以声称总是导致异常。 Pickles实际上是用专门的堆栈语言编写的程序。泡菜的内部细节从版本变为版本,偶尔添加新的泡菜协议。崩溃后的泡菜状态以及对unpickler产生的影响很难在一个简单的声明中总结,例如“它总会导致异常”。
答案 4 :(得分:1)
为了确保你有一个“完整的”pickle文件,你需要挑选三件事。
Pickle某种类型的标题,声称有多少个对象以及文件结束标志的样子。例如,整数元组和EOF字符串。
腌制你真正关心的物品。计数由标题给出。
挑选一个您实际上并不关心的尾部对象,但它只是与标题中的声明相匹配。这可以只是一个匹配标题中的字符串。
当您取消删除此文件时,您必须解开三件事:
标题。你关心计数和尾巴的形式。
您真正关心的对象。
尾巴对象。检查它是否与标题匹配。除此之外,它并没有传达太多,除了文件是完整的。