You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何正确unpickle类对象?解决pickle仅读取首行数据问题

问题描述

当前代码除unpickle反序列化数据环节外均可正常运行:程序从.txt文件逐行读取内容,每行包含5个变量,原本用于赋值给players类的实例对象。但执行unpickle操作时,仅能读取到.txt文件首行对应的pickle数据,无法获取全部内容。
已尝试多种pickle数据写入方式,判断问题出在pickle写入逻辑中。

相关代码

读取txt文件并执行pickle写入的代码段

import pickle
import re

class players:
    def __init__(players,lastName,firstName,games,total,position):
        players.lastName = lastName
        players.firstName = firstName
        players.games = games
        players.total = total
        players.position = position

# Transfer Team Details
def transferDetails():
    exists = False
    while exists == False:
        try:
            file = input("\nPlease enter the text file name: ")
            text_file = open(file + ".txt", "r")
            binary_File = open(file + ".dat", "wb")
            exists = True
            for line in text_file.readlines():
                lastName,firstName,games,total,position = [str(i.strip()) for i in line.split(',')] # Assign here
                lastName = lastName[0:20]# Truncate
                lastName = re.sub(r'[^a-zA-Z]', '', lastName)# Cleaning
                firstName = firstName[0:20]# Truncate
                firstName = re.sub(r'[^a-zA-Z]', '', firstName)# Cleaning
                # Changing position to default if not set correctly
                if position != "Forward" and position != "Centre" and position != "Guard" :
                    position = "Guard"
                ### Changing games to valid number: 0-200
                games = float(games)
                if games < 0 :
                    games = 0
                elif games > 200 :
                    games = 0
                ### Changing total points value to valid number: 0-1000
                total = float(total)###
                if total < 0 :
                    total = 0
                elif total > 1000 :
                    total = 0
                pickle.dump(lastName, binary_File)
                pickle.dump(firstName, binary_File)
                pickle.dump(games, binary_File)
                pickle.dump(total, binary_File)
                pickle.dump(position, binary_File)
                binary_File.close
                ###TESTING ONLY###
                print("Last Name: ", lastName)
                print("First Name : ", firstName)
                print("Games played: ", games)
                print("Total points: ", total)
                print("Position: ", position)
                print("\n\n")
                ###TESTING ONLY###
        ### File not found
        except FileNotFoundError:
            print("File not found")

unpickle读取数据的代码段

def listPlayers():
    #Input Code Here
    file2 = input("\nPlease enter the binary file name: ")
    with open(file2 + ".dat", 'rb') as binary_File:
        lastName = pickle.load(binary_File)
        firstName = pickle.load(binary_File)
        games = pickle.load(binary_File)
        total = pickle.load(binary_File)
        position = pickle.load(binary_File)
        print(lastName)
        print(firstName)
        print(games)
        print(total)
        print(position)
运行异常表现

原始.txt文件共包含4行球员数据,对应4个独立的球员对象,但实际执行unpickle函数仅输出1条球员记录:

Please enter the binary file name: test1
bob
billy
10.0
40.0
Guard
问题原因与修复方法

核心错误点

  • 写入逻辑存在两处错误:
    1. 文件关闭语句binary_File.close未添加括号,不会实际执行文件关闭操作,写入缓冲区中除第一行外的剩余数据不会被刷入磁盘,后续行数据实际没有存入.dat文件
    2. 文件关闭语句被错误放在逐行读取的for循环内部,即便补充括号调用关闭方法,第一次循环写完第一行数据后文件就会被关闭,后续行写入会直接报错
  • 读取逻辑存在一处错误:
    仅执行了5次pickle.load()读取第一组共5个字段,没有循环读取文件内所有序列化内容,即便写入的文件数据完整,也只能拿到第一条记录

修复后代码

写入逻辑修复

推荐使用with上下文管理器自动处理文件关闭,不需要手动写close,同时可以直接序列化players类实例,不需要分开dump5个字段,代码更简洁:

def transferDetails():
    while True:
        try:
            file = input("\nPlease enter the text file name: ")
            # 自动管理两个文件的关闭
            with open(file + ".txt", "r") as text_file, open(file + ".dat", "wb") as binary_File:
                for line in text_file.readlines():
                    # 跳过空行避免报错
                    if not line.strip():
                        continue
                    lastName,firstName,games,total,position = [i.strip() for i in line.split(',')]
                    lastName = re.sub(r'[^a-zA-Z]', '', lastName[0:20])
                    firstName = re.sub(r'[^a-zA-Z]', '', firstName[0:20])
                    if position not in ("Forward", "Centre", "Guard"):
                        position = "Guard"
                    # 数值校验,增加非数值输入兼容
                    try:
                        games = float(games)
                    except:
                        games = 0
                    games = 0 if games <0 or games>200 else games
                    try:
                        total = float(total)
                    except:
                        total =0
                    total =0 if total <0 or total>1000 else total
                    # 直接序列化players实例
                    player = players(lastName, firstName, games, total, position)
                    pickle.dump(player, binary_File)
                    # 测试打印
                    print(f"Last Name: {lastName}\nFirst Name: {firstName}\nGames played: {games}\nTotal points: {total}\nPosition: {position}\n\n")
            break
        except FileNotFoundError:
            print("File not found")

读取逻辑修复

循环执行pickle.load(),直到捕获到文件结束抛出的EOFError时停止读取,即可拿到所有球员数据:

def listPlayers():
    file2 = input("\nPlease enter the binary file name: ")
    player_list = []
    with open(file2 + ".dat", 'rb') as binary_File:
        while True:
            try:
                player = pickle.load(binary_File)
                player_list.append(player)
                # 打印球员信息
                print(player.lastName)
                print(player.firstName)
                print(player.games)
                print(player.total)
                print(player.position)
                print("---")
            except EOFError:
                # 读取到文件末尾,退出循环
                break
    print(f"共读取到{len(player_list)}条球员记录")

注意:如果不想序列化类实例,保持原有分开dump5个字段的写法,读取时每次循环连续load5个字段即可,逻辑和上述读取实例的方式一致,直到捕获EOFError停止。

内容的提问来源于stack exchange,提问作者Emilio

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 13:15:35