Jupyter环境下Python Pickle加载新旧文件时try-except语句抛出EOFError问题排查与解决
问题解析与优化方案
你遇到的EOFError本质是文件指针位置导致的,咱们来拆解一下原因,再看看更优雅的解决方式:
为什么最初的try-except会报错?
在你最初的代码里,你是在同一个with块里尝试两次pickle.load():
with open(filename, "rb") as infile: try: jes[:,:,w_index], emin, emax, smin, smax, num_deltas[:,:,w_index] = pickle.load(infile) except: jes[:,:,w_index], emin, emax, smin, smax = pickle.load(infile)
当处理旧版5变量文件时,第一次pickle.load(infile)其实已经把文件里的所有数据都读取出来了(文件里序列化的是一个包含5个元素的元组),只是因为你试图把它解包成6个变量,才抛出了ValueError。这时候文件指针已经移动到了文件末尾,所以当except块里再次调用pickle.load(infile)时,已经没有任何数据可以读取了,自然就触发了EOFError。
你的解决方案为什么有效?
后来你把with语句分别放进try和except块里:
try: with open(jes_comb_path+"/"+file, "rb") as infile: jes_temp, emin, emax, smin, smax, num_deltas[:,:,w_index] = pickle.load(infile) except: with open(jes_comb_path+"/"+file, "rb") as infile: jes_temp, emin, emax, smin, smax = pickle.load(infile)
每次进入try或except时,都会重新打开文件,这意味着文件指针会重置到文件开头。所以当try失败后,except块里重新打开的文件可以从头读取完整的5元素元组,自然不会报错。
更优雅的优化方案
其实不用重复打开两次文件,我们可以先把整个序列化的对象读取出来,再根据元素数量处理,这样效率更高,代码也更清晰:
jes = NP.zeros((ne,ns,nw)) num_deltas = NP.zeros((ne,ns,nw)) w_index = 0 for file in jes_file_list: file_path = f"{jes_comb_path}/{file}" # 用f-string更简洁 with open(file_path, "rb") as infile: data_tuple = pickle.load(infile) # 根据元组长度判断是新版还是旧版文件 if len(data_tuple) == 6: jes_temp, emin, emax, smin, smax, num_deltas[:,:,w_index] = data_tuple else: jes_temp, emin, emax, smin, smax = data_tuple jes[:,:,w_index] = jes_temp w_index += 1
另外建议不要使用裸except,最好捕获特定的异常(比如ValueError),避免意外捕获其他无关错误(比如文件不存在、权限问题等),让代码的错误处理更精准:
try: with open(file_path, "rb") as infile: jes_temp, emin, emax, smin, smax, num_deltas[:,:,w_index] = pickle.load(infile) except ValueError: with open(file_path, "rb") as infile: jes_temp, emin, emax, smin, smax = pickle.load(infile)
内容的提问来源于stack exchange,提问作者BGreen
相关产品推荐
相关产品推荐

