Python:修改已序列化对象

1 投票
1 回答
2517 浏览
提问于 2025-04-16 22:25

我正在使用cPickle来存储对象。之后我想修改其中的某些记录。不幸的是,文件在修改后出现了损坏(我收到了UnpicklingError的错误信息):

创建和序列化

class Book(object):
    def __init__(self, title, author, ISBN, price):
        self.title = title
        self.author = author
        self.ISBN = ISBN
        self.price = price

def main():
    from cPickle import dump
    from random import choice
    from random import randrange
    letters = ("a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k",
           "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v",
           "w", "x", "y", "z")
    f = open("books.dat", "a+b")

    for ctr in range(0, 20):
        title = ""
        author = ""
        ISBN = ""
        price = randrange(20,100)
        for i in range(10):
            title+=choice(letters)
            author+=choice(letters)
            ISBN+=str(randrange(0,14))
        book = Book(title, author, ISBN, price)
        # writing structure
        dump(book, f)
    f.close()
    print "Finished."

main()

反序列化和修改

class Book(object):
    def __init__(self, title, author, ISBN, price):
        self.title = title
        self.author = author
        self.ISBN = ISBN
        self.price = price

    def __str__(self):
        rep = self.title+" by "+self.author+".\n"
        rep += "ISBN: "+self.ISBN+"\n"
        rep += "Price: "+str(self.price)
        return rep

def main():
    from cPickle import load
    from cPickle import dump
    import sys

    books = []
    EOF = False
    f = open("books.dat", "r+b")
    print "Loading..."
    while not EOF:
        try:
            book = load(f)
        except(EOFError):
            EOF = True
        else:
            books.append(book)
    print "Load complete."
    rec = int(raw_input("Record to delete: "))
    print books[rec]
    fwd = 0
    for i in range(rec):
        fwd+= sys.getsizeof(books[i]) 
    print str(fwd)
    title = "New"
    author = "New"
    ISBN = "New"
    price = 0
    new = Book(title, author, ISBN, price)
    print str(sys.getsizeof(new))
    f.seek(fwd)
    dump(new, f)
    f.close()

main()

1 个回答

2

我不太确定,但我觉得既然你已经有了一份从文件中加载的书籍对象列表,那么如果你用这个列表的内容来重写文件,会更简单也更不容易出错。你可以删除你想要的记录,或者直接用 books[i]=new 来替换它们,而不是费劲去找一个地方插入新的记录。

换句话说,可以试试下面的方法:

class Book(object):

    def __init__(self, title, author, ISBN, price):
        self.title = title
        self.author = author
        self.ISBN = ISBN
        self.price = price

    def __str__(self):
        rep = self.title+" by "+self.author+".\n"
        rep += "ISBN: "+self.ISBN+"\n"
        rep += "Price: "+str(self.price)
        return rep

def main():
    from cPickle import load, dump

    print "Loading..."
    books = [load(line) for line in open("books.dat", "rb")]
    print "Load complete."

    rec = int(raw_input("Record to delete: "))        
    title = "New"
    author = "New"
    ISBN = "New"
    price = 0

    books[rec] = Book(title, author, ISBN, price) # replace previous record

    with open("books.dat", "wb") as f:        
        for record in books:
            dump(record, f)


main()

撰写回答