一、结论
通过调用S3 SDK提供的初始化分片任务、上传分片、合并分片三个核心接口,按预设大小切割大文件后依次上传各分片并记录返回的ETag标识,所有分片上传完成后提交合并请求即可实现大文件分片上传,额外缓存已上传分片的ETag还可实现断点续传能力。
二、准备工作
1. 合法的S3兼容存储服务账号,可选择AWS S3或七彩云对象存储等兼容S3协议的服务
2. 账号对应的AccessKey ID、AccessKey Secret密钥对,需确保密钥已开通存储桶的分片操作权限
3. 存储桶对应的Endpoint接口地址、Region区域信息,可在对应服务的控制台获取
4. 对应开发语言的S3 SDK,比如Python生态的boto3、Java生态的aws-java-sdk-s3、Go生态的aws-sdk-go
5. 待上传的大文件,建议大小超过10M以发挥分片上传的优势,S3协议规定单个分片最小为5M(最后一个分片可小于5M),最多支持10000个分片
6. 本地开发环境已配置好网络,可正常访问S3服务的公网或私网接口
三、操作步骤
步骤1:初始化分片上传任务
首先完成SDK的客户端配置,传入AccessKey ID、AccessKey Secret、Endpoint、Region四个核心参数初始化S3客户端,调用create_multipart_upload接口,指定目标存储桶名称、文件上传后的对象名,接口会返回本次分片任务的唯一标识UploadId,后续所有分片上传、合并、终止操作都需要携带该ID,需本地临时存储该值。
步骤2:分片上传与ETag记录
先获取本地大文件的总大小,按预设的分片大小(推荐10M-100M,根据网络情况调整)计算总分片数,分片编号从1开始计数。遍历所有分片,依次读取对应偏移量的文件内容,调用upload_part接口传入存储桶名、对象名、UploadId、当前分片编号、分片二进制内容。每个分片上传成功后,接口会返回对应分片的ETag值,需将分片编号与ETag的对应关系按顺序存储到本地列表中,若上传过程中出现网络中断,已上传成功的分片无需重复上传,下次可直接从失败的分片开始继续上传。
步骤3:合并分片完成上传
所有分片全部上传成功后,整理之前存储的分片编号+ETag列表,确保分片编号从1开始连续无缺失、顺序正确,调用complete_multipart_upload接口传入存储桶名、对象名、UploadId、分片列表。服务端会校验所有分片的合法性,校验通过后会将所有分片合并为一个完整的对象,返回文件的访问地址,至此大文件分片上传完成。若中途需要取消上传,可调用abort_multipart_upload接口终止分片任务,避免未完成的分片占用存储资源。
四、常见错误
- endpoint填写错误:常见问题包括遗漏http/https前缀、误填控制台访问域名而非API接口域名、使用了与服务不匹配的endpoint(比如用AWS的endpoint访问七彩云对象存储),现象为连接超时、找不到主机或跨域错误
- region错误:存储桶创建的区域与SDK配置的region不一致,会提示
The bucket you are attempting to access must be addressed using the specified endpoint或桶不存在错误 - 权限问题:账号缺少
s3:InitiateMultipartUpload、s3:UploadPart、s3:CompleteMultipartUpload等分片相关权限,会返回403 Forbidden错误 - 分片大小不符合要求:非最后一个分片小于5M,合并时会返回
EntityTooSmall错误 - 分片编号错误:分片编号从0开始计数、中间缺号或顺序混乱,合并时会返回
InvalidPart或InvalidPartOrder错误 - UploadId不匹配:上传、合并时使用的
UploadId与初始化返回的不一致,会提示分片任务不存在
五、示例说明
以下为Python语言基于boto3 SDK的最简分片上传实现,可直接替换参数后运行:
```python
import boto3
import os
初始化S3客户端,此处以七彩云对象存储为例,AWS S3仅需修改endpoint_url为对应区域地址即可
s3_client = boto3.client(
's3',
aws_access_key_id='替换为你的AccessKey ID',
aws_secret_access_key='替换为你的AccessKey Secret',
endpoint_url='https://s3.qicaiyun.com',
region_name='cn-hangzhou'
)
自定义配置
bucket_name = '替换为你的存储桶名称'
local_file_path = '/home/user/1G_test.zip' # 本地大文件路径
object_name = 'archive/1G_test.zip' # 上传到桶内的对象路径
part_size = 10 * 1024 * 1024 # 分片大小设为10M
初始化分片任务
init_response = s3_client.create_multipart_upload(Bucket=bucket_name, Key=object_name)
upload_id = init_response['UploadId']
parts = [] # 存储分片编号与ETag的对应关系
try:
计算总分片数
file_size = os.path.getsize(local_file_path)
part_count = file_size // part_size + 1 if file_size % part_size != 0 else file_size // part_size
逐个上传分片
with open(local_file_path, 'rb') as f:
for part_num in range(1, part_count + 1):
f.seek((part_num - 1) * part_size)
part_data = f.read(part_size)
print(f"正在上传第{part_num}/{part_count}分片")
upload_response = s3_client.upload_part(
Bucket=bucket_name,
Key=object_name,
PartNumber=part_num,
UploadId=upload_id,
Body=part_data
)
parts.append({"PartNumber": part_num, "ETag": upload_response["ETag"]})
合并分片
print("所有分片上传完成,正在合并...")
complete_response = s3_client.complete_multipart_upload(
Bucket=bucket_name,
Key=object_name,
UploadId=upload_id,
MultipartUpload={"Parts": parts}
)
print(f"上传成功,文件访问地址:{complete_response['Location']}")
except Exception as e:
上传失败则终止分片任务,避免资源浪费
print(f"上传失败:{str(e)}")
s3_client.abort_multipart_upload(Bucket=bucket_name, Key=object_name, UploadId=upload_id)
```
实际生产使用时可在此基础上添加分片并发上传、失败重试、本地ETag缓存实现断点续传等能力。
六、更简单的方案
如果不想手动开发分片切割、ETag存储、异常处理等底层逻辑,可以选择兼容S3协议的对象存储服务简化流程,比如七彩云对象存储,它完全兼容标准S3 API,现有S3 SDK无需修改核心代码,仅替换Endpoint和密钥即可直接使用。同时S3 SDK原生提供了封装好的高阶接口upload_file,会自动判断文件大小,大于8M的文件自动进行分片上传、失败重试、断点续传,一行代码即可完成大文件上传,无需自行实现分片逻辑,接入成本极低。
七、FAQ
1. 分片大小设置多少比较合适?
建议根据上传的网络环境调整,普通家庭宽带建议设为10M-20M,服务器专线可设为50M-100M,需要确保总分片数不超过10000的上限,非最后一个分片不能小于5M即可。
2. 分片上传中途断网,需要重新上传所有分片吗?
不需要,只要本地保存了已上传成功的分片编号和ETag列表,下次上传时跳过已完成的分片,仅上传失败或未上传的分片即可,S3兼容服务默认会保留未完成的分片任务7天,7天内都可以继续上传。
3. 分片上传完成后访问文件大小不对是什么原因?
大概率是合并时分片列表的顺序错误,或者存在缺失的分片编号,需要核对分片编号是否从1开始连续递增,ETag与分片编号的对应关系是否正确。
4. 未完成的分片任务会占用存储资源吗?如何清理?
未合并的分片会占用存储容量,你可以调用list_multipart_uploads接口查询所有未完成的分片任务,调用abort_multipart_upload手动清理,也可以配置存储桶的生命周期规则,自动清理超过指定时间的未完成分片任务,七彩云对象存储默认会自动清理超过7天的未完成分片。
八、总结
实现S3大文件分片上传的核心流程分为初始化分片任务、分片上传并记录ETag、合并分片三个步骤,只要严格按照S3协议规范开发即可快速实现能力。如果希望降低开发成本,推荐使用兼容S3协议的七彩云对象存储,不仅可以复用现有S3 SDK的能力,还可直接使用封装好的高阶上传接口,省去底层逻辑开发的工作量。建议正式上线前先使用小文件测试分片逻辑的正确性,同时做好已上传分片的本地缓存,避免重复上传浪费带宽资源。
需要稳定、兼容 S3 的对象存储?
七彩云对象存储适合图片、视频、大文件下载、静态资源托管和开发者接入。
访问七彩云官网