Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/351.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 为什么';添加二元泡菜不行吗?_Python_Pickle - Fatal编程技术网

Python 为什么';添加二元泡菜不行吗?

Python 为什么';添加二元泡菜不行吗?,python,pickle,Python,Pickle,我知道这并不是pickle模块的预期用途,但我认为这会起作用。我正在使用Python 3.1.2 以下是背景代码: import pickle FILEPATH='/tmp/tempfile' class HistoryFile(): """ Persistent store of a history file Each line should be a separate Python object Usually, pickle is used to m

我知道这并不是pickle模块的预期用途,但我认为这会起作用。我正在使用Python 3.1.2

以下是背景代码:

import pickle

FILEPATH='/tmp/tempfile'

class HistoryFile():
    """
    Persistent store of a history file  
    Each line should be a separate Python object
    Usually, pickle is used to make a file for each object,
        but here, I'm trying to use the append mode of writing a file to store a sequence
    """

    def validate(self, obj):
        """
        Returns whether or not obj is the right Pythonic object
        """
        return True

    def add(self, obj):
        if self.validate(obj):
            with open(FILEPATH, mode='ba') as f:    # appending, not writing
                f.write(pickle.dumps(obj))
        else:
            raise "Did not validate"

    def unpack(self):
        """
        Go through each line in the file and put each python object
        into a list, which is returned
        """
        lst = []
        with open(FILEPATH, mode='br') as f:
            # problem must be here, does it not step through the file?
            for l in f:
                lst.append(pickle.loads(l))
        return lst
现在,当我运行它时,它只打印出传递给类的第一个对象

if __name__ == '__main__':

    L = HistoryFile()
    L.add('a')
    L.add('dfsdfs')
    L.add(['dfdkfjdf', 'errree', 'cvcvcxvx'])

    print(L.unpack())       # only prints the first item, 'a'!

这是因为它看到了早期EOF吗?可能追加只用于ascii?(在这种情况下,为什么它允许我执行mode='ba'?)有更简单的duh方法来执行此操作吗?

为什么您认为附加二进制pickle会产生单个pickle?!pickle允许您一个接一个地放置(并取回)多个项,因此显然它必须是一种“自终止”序列化格式。忘记台词,把它们拿回来!例如:

>>> import pickle
>>> import cStringIO
>>> s = cStringIO.StringIO()
>>> pickle.dump(23, s)
>>> pickle.dump(45, s)
>>> s.seek(0)
>>> pickle.load(s)
23
>>> pickle.load(s)
45
>>> pickle.load(s)
Traceback (most recent call last):
   ...
EOFError
>>> 

只要捕捉到
EOFError
来告诉您何时完成取消勾选。

答案是它确实可以工作,但如果没有模式中的“+”,则由open的append功能自动添加的换行符会将二进制与字符串数据混在一起(明确的否)。更改此行:

with open(FILEPATH, mode='ab') as f:    # appending, not writing
    f.write(pickle.dumps(obj))

Alex还指出,要获得更大的灵活性,请使用mode='r+b',但这需要进行适当的搜索。因为我想创建一个历史文件,它的行为类似于Python对象的先入后出序列,所以我尝试在文件中添加对象是有意义的。我只是做得不对:)

不需要单步遍历该文件,因为它是序列化的。因此,请替换:

for l in f:
    lst.append(pickle.loads(l))


我不知道pickle模块,我的python I/O有点生疏,但我的猜测是,您可能正在从文件中读取行,而对象存储时没有换行符分隔(实际上,可能包含换行符,所以如果是这样的话,您可能想更改),是的,但类必须打开文件以获得写权限,这会删除文件。我想保留它。这就是为什么我想附加这个文件。那么,在开始写作之前阅读内容的标准做法是什么呢?@Adam,只需使用
'r+'
(或者更好的'r+b',这样你就可以使用
pickle.HIGHEST_protocol
的协议进行选择!),cfr和@Alex得到了它;谢谢在公开赛中,我没有对+给予足够的关注。真的很简单。但是仍然不确定最高的_协议是什么,在python3中,他们推荐协议3,这是默认的@Adam,
HIGHEST\u PROTOCOL
,又名
-1
,意思是“你能做的最好”,并且是你应该一直使用的,除非你需要你的pickle可以被旧版本的Python加载。在Python2.*中,默认值是0(ascii协议),因此它必须保持向后兼容性——就像在Python3中必须保持3.*永远如此,即使明天有人发明了一种占用一半时间和空间的新格式(我知道不太可能;-)。因此,如果您不想制作可供较旧Python版本读取的pickle,请始终使用-1!)只是尝试了一下,mode='r+b'似乎不起作用。看了看文档,现在理解得更好了,我尝试了“a+b”,效果和预期一样。我知道pickle不是这样构思的,但事实证明,您可以向文件写入一系列pickle项!
for l in f:
    lst.append(pickle.loads(l))
while 1:
    try:
        lst.append(pickle.load(f))
    except IOError:
        break