使用boto3进行Multipart upload遇阻,求概念与语法详解
S3 Multipart Upload 概念详解与Boto3实现细节
嘿,我来帮你把S3分片上传的事儿掰扯清楚——这玩意儿初上手确实容易踩坑,咱们从概念到Boto3的具体实现一步步来。
什么是Multipart Upload?
简单来说,这是AWS S3针对大文件(或者不稳定网络环境)设计的上传机制:把一个大文件拆成多个**小分片(Part)**分别上传,等所有分片都传完后,再让S3把这些分片合并成一个完整的文件。
它的核心优势:
- 某个分片传失败了?不用重新传整个文件,只重传那个出错的分片就行
- 可以并行上传多个分片,大幅提升上传速度
- 天然支持断点续传,中途断网了下次接着传就行
AWS官方建议:当文件大小超过100MB时,优先使用分片上传;如果文件超过5GB,那必须用分片上传(普通上传不支持这么大的文件)。
Boto3实现Multipart Upload的完整流程
Boto3的S3客户端提供了三个核心方法来完成整个流程,咱们逐个拆解:
1. 初始化分片上传(create_multipart_upload)
这一步相当于给S3打个招呼:“我要开始传一个大文件啦,给我个专属ID呗”。S3会返回一个唯一的UploadId,后续所有分片上传、合并操作都得带着这个ID。
代码示例:
import boto3 # 初始化S3客户端 s3_client = boto3.client('s3') # 发起分片上传请求 response = s3_client.create_multipart_upload( Bucket='your-bucket-name', # 你的S3桶名 Key='documents/large-report.pdf' # 文件在桶里的路径/文件名 ) # 保存关键的UploadId upload_id = response['UploadId']
语法细节:
Bucket和Key是必填参数,Key就是文件最终在S3中的存储路径- 你还可以加额外参数,比如
ContentType='application/pdf'指定文件类型,ACL='private'设置文件权限,这些和普通S3上传的参数逻辑一致 - 如果请求成功,响应里的
UploadId是后续操作的核心凭证,一定要保存好
2. 上传分片(upload_part)
这一步是把文件拆成多个分片,逐个(或者并行)上传到S3。每个分片需要指定唯一的PartNumber(从1开始的整数),上传完成后S3会返回一个ETag——这个是后续合并分片的关键标识。
代码示例:
# 定义分片大小:这里设为10MB(AWS建议最小5MB,最大5GB) part_size = 10 * 1024 * 1024 # 10MB uploaded_parts = [] # 读取本地大文件并分片上传 with open('local-large-report.pdf', 'rb') as file: part_number = 1 while True: # 读取当前分片的内容 chunk_data = file.read(part_size) # 如果没有数据了,说明已经到文件末尾 if not chunk_data: break # 上传当前分片 part_response = s3_client.upload_part( Bucket='your-bucket-name', Key='documents/large-report.pdf', PartNumber=part_number, UploadId=upload_id, Body=chunk_data ) # 保存分片的序号和ETag,后续合并要用 uploaded_parts.append({ 'PartNumber': part_number, 'ETag': part_response['ETag'] }) part_number += 1
语法细节:
PartNumber必须是1到10000之间的整数,每个分片的序号不能重复- 分片大小要求:除了最后一个分片,其他分片的大小必须≥5MB;最后一个分片可以任意大小(哪怕小于5MB)
- 你可以并行上传分片(比如用多线程/多进程),不用按顺序传,但一定要记录好每个分片的
PartNumber和ETag - 如果某个分片上传失败,直接重新上传这个分片就行,不用管其他已经传好的
3. 完成分片上传(complete_multipart_upload)
当所有分片都上传成功后,把收集到的分片信息(PartNumber和ETag)提交给S3,S3会自动把这些分片合并成一个完整的文件,正式完成上传任务。
代码示例:
# 提交合并请求前,一定要把分片按PartNumber升序排序 sorted_parts = sorted(uploaded_parts, key=lambda x: x['PartNumber']) # 完成分片上传 complete_response = s3_client.complete_multipart_upload( Bucket='your-bucket-name', Key='documents/large-report.pdf', UploadId=upload_id, MultipartUpload={ 'Parts': sorted_parts } ) # 合并成功后,会返回文件的S3地址 print(f"文件上传完成,地址:{complete_response['Location']}")
语法细节:
MultipartUpload['Parts']必须是按PartNumber升序排列的列表,哪怕你是乱序上传的分片,这里也必须排序- 如果合并成功,S3会删除所有临时存储的分片,只保留合并后的完整文件
- 如果有分片上传失败,你可以选择放弃整个任务(看下面的中止方法),避免S3保留无用的分片占用存储空间
额外:中止分片上传(abort_multipart_upload)
如果中途不想继续上传了,或者出现无法修复的错误,一定要调用这个方法来中止任务,不然S3会在7天后自动清理这些临时分片,但主动调用更稳妥,能及时释放存储空间。
代码示例:
s3_client.abort_multipart_upload( Bucket='your-bucket-name', Key='documents/large-report.pdf', UploadId=upload_id )
常见坑点提醒
- 分片大小别搞错:除了最后一个分片,其他必须≥5MB,不然会直接报错
- ETag一定要保存正确:每个分片的ETag是S3返回的字符串,不能自己生成,否则合并时会失败
- PartNumber范围要注意:必须在1到10000之间,不能重复
- 合并前一定要排序:哪怕你并行上传的分片顺序乱了,提交Parts的时候必须按PartNumber升序排列
内容的提问来源于stack exchange,提问作者Ganesh Shinde




