Почему не работает добавление бинарных солений? - PullRequest
3 голосов
/ 18 мая 2010

Я знаю, что это не совсем так, как предполагалось использовать модуль рассола, но я бы подумал, что это сработает Я использую 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'?) Есть ли гораздо более простой способ сделать это?

Ответы [ 2 ]

6 голосов
/ 18 мая 2010

С чего вы взяли, что добавление бинарных солений приведет к получению одного соленья ?! Pickling позволяет вам помещать (и возвращать) несколько элементов один за другим, поэтому очевидно, что это должен быть «самозавершающийся» формат сериализации. Забудь о строках и просто верни их! Например:

>>> 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, чтобы сообщить вам, когда вы закончите расстегивать.

4 голосов
/ 19 мая 2010

Ответ заключается в том, что он работает, но без режима «+» символы новой строки, автоматически добавляемые функцией добавления open, смешивают двоичный файл со строковыми данными (определенно нет-нет). Измените эту строку:

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

до

with open(FILEPATH, mode='a+b') as f:    # appending, not writing
    pickle.dump(obj, f)

Алекс также указывает, что для большей гибкости используйте mode = 'r + b', но это требует соответствующего поиска. Так как я хотел создать файл истории, который бы вел себя как последовательность элементов типа «питон» в порядке «первым пришел - последним вышел», для меня действительно имел смысл попробовать добавить объекты в файл. Я просто не делал это правильно:)

Нет необходимости просматривать файл, потому что (да!) Он сериализован. Так что замените:

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

с

while 1:
    try:
        lst.append(pickle.load(f))
    except IOError:
        break
...