通过boto3从S3下载Pickle文件偶发损坏报EOFError是什么原因
S3下载Pickle文件触发EOFError的常见原因
- 下载过程被意外截断,未捕获异常
你当前的下载代码没有添加任何异常处理逻辑,当遇到网络抖动、临时限速、连接超时等问题时,boto3的download_fileobj可能会提前终止执行,但此时已经被创建的本地文件会被正常关闭,最终得到一个内容不完整的文件。pickle加载截断的文件时就会抛出EOFError。S3控制台下载内置了断点续传、自动重试逻辑,网络异常时会自动重试,所以手动下载的文件不会损坏。 - 下载与加载逻辑时序冲突
如果你的下载逻辑是异步执行的,可能出现下载任务还未完全执行完毕,提前触发了pickle加载逻辑,此时文件还在写入中,内容不完整就会触发报错。 - S3客户端配置不合理
boto3默认的重试次数、超时阈值对大文件或者弱网场景适配性不足,如果你的Pickle文件体积偏大,默认配置下可能出现下载超时直接终止的情况,不会触发重试,最终得到不完整的文件。 - 本地写入环境异常
如果下载目标路径的磁盘剩余空间不足、或者当前进程没有目标路径的完整写入权限,可能出现文件只写入了部分内容就被终止的情况,也会触发该问题。 - boto3版本存在已知Bug
部分旧版本boto3的download_fileobj方法存在边界处理缺陷,处理特定大小的文件时会提前终止写入,升级boto3到最新稳定版即可解决。
快速验证修复方案
你可以通过增加文件完整性校验逻辑排查问题,修改下载函数如下:
import boto3 import os def download_resource(key: str, dest: str): s3 = boto3.client('s3') # 先获取对象元信息拿到预期文件大小 obj_meta = s3.head_object(Bucket=BUCKET, Key=key) expected_size = obj_meta['ContentLength'] with open(dest, 'wb') as f: s3.download_fileobj(BUCKET, key, f) # 校验本地文件大小是否符合预期 actual_size = os.path.getsize(dest) if actual_size != expected_size: # 可在这里增加重试逻辑 raise RuntimeError(f"文件下载不完整,预期大小{expected_size},实际大小{actual_size}")
也可以在初始化s3客户端时主动调整重试和超时配置,适配大文件下载场景。
内容的提问来源于stack exchange,提问作者Alexander Soare
相关产品推荐
相关产品推荐

