反序列化错误:无效加载键'(heart)

1 投票
1 回答
2480 浏览
提问于 2025-04-18 08:05

我最近在玩一个叫pickle的东西,想把它用在一个“猜数字”练习程序的高分系统里。我以为我已经理解这个概念了,但现在出现了一个错误,我完全不知道为什么。

这是相关的代码:

def EnterHighScore(score,scoresList):
    name = input("Enter your name: ")
    newPlayer = player(name,score)
    scoresList.append(newPlayer)
    scoresFile = open('scores','wb')
    pickle.dump(scoresList,scoresFile)
    scoresFile.close()

    for i in scoresList:
        print(i.name + ' - ' + str(i.score))

def CheckHighScores(score):
    try:
        scoresFile = open('scores','rb')
    except:
        scoresFile = open('scores','wb+')

    if not scoresFile.read(1):
        scoresList = []
    else:
        scoresList = pickle.load(scoresFile)
    scoresFile.close()

    if not scoresList:
        EnterHighScore(score,scoresList)
    else:
        for counter,i in enumerate(scoresList):
            if counter == 3:
                break
            if score >= i.score:
                EnterHighScore(score,scoresList)
                break

当我运行这个程序时,第一次运行是没问题的。也就是说,当'scores'文件根本不存在的时候,它会正确创建这个文件,scoresList会先是空的,然后填入一个玩家对象,最后把它保存到scoresFile里,没有任何错误。但是当我尝试用新的'scores'文件数据来加载scoresList时,就出现了以下错误:

UnpicklingError: Invalid load key'(heart)'

(心)代表一个实际的心形字符。

我看到其他人也遇到过这个问题,但他们的情况是因为在不同的操作系统上打开文件,或者在序列化后但反序列化前修改了文件。而在我的情况下,这个文件根本没有被修改,只是写入并关闭了。

我还尝试在其他更简单的场景中使用pickle,结果没有出现其他错误。

任何帮助都会很感激。

1 个回答

2

你用来检查文件是否为空的测试,会把文件读取指针移动到文件的开头之后:

if not scoresFile.read(1):

你需要把指针再移回到开头:

if not scoresFile.read(1):
    scoresList = []
else:
    scoresFile.seek(0)
    scoresList = pickle.load(scoresFile)

一个更好的方法是捕获 pickle.load() 抛出的 EOFError 异常,这个异常会在文件为空时出现:

try:
    scoresList = pickle.load(scoresFile)
except EOFError:
    # File empty
    scoresList = []

或者你可以捕获 IOError,当文件不存在时就会出现这个错误:

try:
    with open('scores','rb') as scoresFile:
        scoresList = pickle.load(scoresFile)
except IOError:
    scoresList = []

这样你就可以在这里不打开文件进行写入了。

撰写回答