如果酸洗被中断,那么取消涂层肯定会失败吗? - Python

时间:2009-10-31 09:38:20

标签: python

假设由于崩溃,我将pickle对象写入磁盘的尝试不完整。尝试取消对象总是会导致异常,或者写出的片段是否可能被解释为有效的pickle并且错误会被忽视?

5 个答案:

答案 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_filesafe_read_file。)

答案 3 :(得分:1)

我怀疑你是否可以声称​​总是导致异常。 Pickles实际上是用专门的堆栈语言编写的程序。泡菜的内部细节从版本变为版本,偶尔添加新的泡菜协议。崩溃后的泡菜状态以及对unpickler产生的影响很难在一个简单的声明中总结,例如“它总会导致异常”。

答案 4 :(得分:1)

为了确保你有一个“完整的”pickle文件,你需要挑选三件事。

  1. Pickle某种类型的标题,声称有多少个对象以及文件结束标志的样子。例如,整数元组和EOF字符串。

  2. 腌制你真正关心的物品。计数由标题给出。

  3. 挑选一个您实际上并不关心的尾部对象,但它只是与标题中的声明相匹配。这可以只是一个匹配标题中的字符串。

  4. 当您取消删除此文件时,您必须解开三件事:

    1. 标题。你关心计数和尾巴的形式。

    2. 您真正关心的对象。

    3. 尾巴对象。检查它是否与标题匹配。除此之外,它并没有传达太多,除了文件是完整的。