使用续传令牌从S3下载文件时出现错误的技术求助
解决S3批量小文件下载中的续传令牌问题
我来帮你搞定这个S3批量小文件下载的坑!你的代码目前有两个核心问题:没正确处理S3分页的续传令牌,导致无法遍历所有对象;另外代码只实现了列出对象Key到CSV,还没完成实际下载逻辑。下面一步步给你修复和完善:
问题分析
- 续传令牌缺失:S3的
list_objects_v2默认每次最多返回1000个对象,当桶里的文件超过这个数时,会返回NextContinuationToken,你必须把这个令牌传入下一次请求才能获取剩余对象。你的代码里完全没处理这个,所以要么只能拿到前1000个对象,要么循环会提前终止。 - 无实际下载逻辑:你目前只是把Key写入CSV,但没实现下载文件的代码。
- CSV写入不规范:每个Key后面没加换行,导致所有Key都挤在一起,后续根本没法用。
修复后的完整代码
import boto3 import os from botocore.exceptions import ClientError def download_s3_small_files(bucket, local_root_dir='/Users/hr/Desktop/s3_backup'): # 初始化S3客户端 s3 = boto3.client('s3') kwargs = {'Bucket': bucket} # 创建本地根目录(如果不存在) os.makedirs(local_root_dir, exist_ok=True) # 保存对象Key的CSV路径 csv_path = os.path.join(local_root_dir, 'files.csv') with open(csv_path, 'w') as file: while True: try: # 发起S3对象列表请求 resp = s3.list_objects_v2(**kwargs) except ClientError as e: print(f"获取对象列表时出错: {e.response['Error']['Message']}") return # 检查是否有对象内容 if 'Contents' not in resp: print("没有更多对象可遍历") break # 遍历当前页的所有对象 for obj in resp['Contents']: key = obj['Key'] # 写入CSV时添加换行 file.write(f"{key}\n") # 构建本地保存路径 local_file_path = os.path.join(local_root_dir, key) # 创建文件所在的目录(如果不存在) local_dir = os.path.dirname(local_file_path) os.makedirs(local_dir, exist_ok=True) try: # 下载文件到本地 s3.download_file(bucket, key, local_file_path) print(f"成功下载: {key}") except ClientError as e: print(f"下载失败 {key}: {e.response['Error']['Message']}") # 检查是否有续传令牌,准备下一页请求 if 'NextContinuationToken' in resp: kwargs['ContinuationToken'] = resp['NextContinuationToken'] else: # 没有更多页,退出循环 break # 调用函数,替换成你的桶名 download_s3_small_files(bucket='your-bucket-name')
关键修复点说明
- 续传令牌处理:每次请求后检查
resp['NextContinuationToken'],如果存在就把它放到kwargs里,下一次请求会自动获取下一页的对象,直到没有令牌为止,确保遍历桶里所有对象。 - 本地目录自动创建:用
os.makedirs(..., exist_ok=True)自动创建S3 Key对应的目录结构,避免下载时因为目录不存在报错。 - 完善的异常处理:捕获
ClientError来处理S3权限不足、对象不存在等常见问题,方便排查错误。 - 规范的CSV写入:每个Key后面添加换行符,保证CSV文件的可读性。
额外优化建议
如果你的小文件数量特别多(比如几万甚至几十万),可以考虑:
- 多线程/多进程下载:用
concurrent.futures.ThreadPoolExecutor来并行下载,提升速度(小文件适合多线程,因为IO等待时间长)。 - 调整分页大小:在
kwargs里添加MaxKeys=1000(最大允许值),减少请求次数。 - 日志记录:把下载成功/失败的日志写入文件,方便后续核对。
内容的提问来源于stack exchange,提问作者Hazzamataza
相关产品推荐
相关产品推荐

