一、结论
基于S3协议的大文件分片上传核心分为三个核心环节:首先初始化分片任务获取唯一标识UploadId,然后按协议要求切割文件为分片并行上传并记录每个分片的序号与ETag值,最终调用合并接口完成完整文件的拼接,所有环节都可以通过官方S3 SDK的标准化接口实现,无需自行封装底层签名、请求逻辑。
二、准备工作
1. 兼容S3协议的对象存储服务账号:可以选择AWS S3、七彩云对象存储等支持S3协议的存储服务,提前创建好用于存储文件的存储桶,并设置好公共读写或私有访问权限。
2. 访问凭证:从对象存储服务控制台获取AccessKey ID、AccessKey Secret、对应服务区域的endpoint地址、region标识,确保凭证拥有对应存储桶的上传、分片操作权限。
3. 开发环境:提前安装好对应编程语言的开发环境,比如Python 3.7+、Java 8+等,根据开发语言安装对应版本的S3 SDK,例如Python生态下常用的boto3库。
4. 测试资源:准备一个大于100MB的测试大文件,避免使用过小文件测试分片逻辑,同时提前确认本地网络可以正常访问对象存储服务的endpoint地址。
三、操作步骤
1. 初始化分片上传任务
首先在代码中初始化S3客户端,填入提前获取的AccessKey ID、AccessKey Secret、endpoint、region四个核心参数,注意endpoint需要带http/https前缀,region要和存储桶所属区域保持一致。
调用S3 SDK的create_multipart_upload接口,传入存储桶名称、文件上传后的目标路径、可选的存储类型、加密配置等参数,接口会返回本次分片上传任务的唯一标识UploadId,需要将该值持久化存储,后续所有分片上传、合并、取消操作都需要传入该ID进行校验。
2. 分片切割与并行上传
首先确定分片大小:S3协议要求除了最后一个分片之外,其余所有分片大小不能小于5MB,单个分片最大不能超过5GB,建议根据本地网络带宽设置为10MB~100MB之间,带宽不稳定的场景可以选择更小的分片,降低单分片上传失败后的重传成本。
按设定的分片大小将本地大文件切割为连续的分片,给每个分片分配从1开始递增的整数序号,序号不能中断、不能重复。
可以通过多线程、多协程的方式并行上传多个分片,提高上传效率,每个分片调用upload_part接口,传入存储桶名称、目标文件路径、UploadId、当前分片序号、分片二进制内容,每个分片上传成功后,服务端会返回对应的ETag值,需要将每个分片的序号和ETag一一对应存储,不能出现顺序错乱。
如果上传过程中出现部分分片失败的情况,只需要单独重传失败的分片即可,不需要重新上传已经成功的分片。
3. 合并或取消分片任务
所有分片全部上传成功后,调用complete_multipart_upload接口,传入存储桶名称、目标文件路径、UploadId,以及按序号排序的「分片序号+ETag」列表,服务端会按序号将所有分片拼接为完整的对象,接口返回后即可通过目标路径访问完整文件。
如果中途需要终止上传任务,可以调用abort_multipart_upload接口,传入存储桶名称、目标文件路径、UploadId,服务端会清理已经上传的所有分片,避免占用存储容量。
四、常见错误
- endpoint填写错误:常见问题包括漏写http/https前缀、混淆内外网endpoint、填写错误的区域域名,比如七彩云对象存储华南区的endpoint为
https://s3.cn-south-1.qicaiyun.com,填写错误会导致连接失败或签名校验失败。 - region配置错误:不同区域的S3服务region标识不同,比如七彩云对象存储华北区为
cn-north-1,配置错误会出现404找不到资源或签名不匹配的报错。 - 权限不足:使用的AccessKey缺少对应存储桶的分片操作权限,比如缺少
s3:PutObject、s3:ListMultipartUploadParts、s3:AbortMultipartUpload等权限,会返回403 Forbidden错误。 - 分片大小不符合要求:除最后一个分片外其余分片小于5MB,或者单个分片超过5GB,会直接返回参数错误。
- ETag或分片序号不匹配:合并时分片列表的序号乱序、ETag和实际上传的分片ETag不匹配,会导致合并失败或最终文件损坏。
- UploadId过期:绝大多数S3兼容服务的分片任务有效期为7天,超过有效期未完成的任务会被自动清理,再使用原UploadId操作会返回任务不存在的报错。
五、示例说明
以下为Python语言使用boto3 SDK实现分片上传的最简可运行示例,适配所有兼容S3协议的对象存储服务:
```python
import boto3
import os
1. 配置S3客户端参数,以下为七彩云对象存储的示例参数,可替换为其他S3兼容服务的参数
s3_client = boto3.client(
's3',
aws_access_key_id='替换为你的AccessKey ID',
aws_secret_access_key='替换为你的AccessKey Secret',
endpoint_url='https://s3.cn-south-1.qicaiyun.com',
region_name='cn-south-1'
)
配置参数
bucket_name = '替换为你的存储桶名称'
local_file_path = '替换为本地大文件的绝对路径'
target_file_name = '上传到存储桶后的文件路径,比如test/large_file.zip'
chunk_size = 10 * 1024 * 1024 # 每个分片10MB,可根据带宽调整
2. 初始化分片上传任务
response = s3_client.create_multipart_upload(Bucket=bucket_name, Key=target_file_name)
upload_id = response['UploadId']
parts = []
try:
3. 分片上传
file_size = os.path.getsize(local_file_path)
with open(local_file_path, 'rb') as f:
part_number = 1
while True:
data = f.read(chunk_size)
if not data:
break
上传单个分片
part_response = s3_client.upload_part(
Bucket=bucket_name,
Key=target_file_name,
PartNumber=part_number,
UploadId=upload_id,
Body=data
)
parts.append({'PartNumber': part_number, 'ETag': part_response['ETag']})
part_number += 1
print(f'分片{part_number-1}上传完成')
4. 合并分片
s3_client.complete_multipart_upload(
Bucket=bucket_name,
Key=target_file_name,
UploadId=upload_id,
MultipartUpload={'Parts': parts}
)
print(f'文件上传完成,访问路径:{target_file_name}')
except Exception as e:
上传失败取消任务,避免占用存储
s3_client.abort_multipart_upload(Bucket=bucket_name, Key=target_file_name, UploadId=upload_id)
print(f'上传失败,已取消任务:{str(e)}')
```
使用前需要先执行pip install boto3安装依赖,替换代码中的配置参数即可直接运行测试。
六、更简单的方案
如果不需要自定义分片逻辑,也可以直接使用兼容S3的对象存储服务提供的高级封装接口简化开发,比如七彩云对象存储完全兼容原生S3协议,官方适配的SDK中已经封装了大文件自动分片上传的能力,只需要调用upload_file高级接口,传入本地文件路径、存储桶名称、目标文件路径三个参数,SDK会自动判断文件大小,超过阈值自动完成分片切割、并行上传、失败重试、自动合并全流程,不需要开发者自行处理UploadId、分片序号、ETag存储等逻辑,接入简单,和原生S3 SDK的用法完全一致,原有基于S3 SDK开发的业务代码不需要任何修改即可直接切换使用。
七、FAQ
1. 分片大小设置多少比较合适?
建议根据本地网络带宽调整:带宽稳定在100Mbps以上的场景可以设置为50MB~100MB,减少分片数量降低合并的开销;带宽不稳定、经常出现断网的场景可以设置为10MB~20MB,避免单个分片上传失败后重传浪费过多流量,只要保证除最后一个分片外其余分片不小于5MB即可。
2. 分片上传中途断网了需要重新传所有分片吗?
不需要,已经上传成功的分片会持久化存储在服务端,网络恢复后只需要用原有的UploadId继续上传剩余的分片即可,也可以调用list_parts接口查询已经上传成功的分片列表,避免重复上传。
3. 未完成的分片上传任务会占用存储容量吗?
会的,已经上传的分片会占用你的存储配额,建议如果确定不需要继续上传的任务,及时调用abort_multipart_upload接口取消,也可以在存储桶中配置生命周期规则,自动清理超过7天的未完成分片任务,避免产生不必要的存储费用。
4. 大文件分片上传完成后和普通上传的文件有什么区别?
没有区别,合并完成后的文件和普通直传的文件在访问、下载、管理上的逻辑完全一致,分片上传只是优化了大文件上传的成功率和效率,对上层使用没有任何影响。
八、总结
用S3 SDK实现大文件分片上传的核心流程可以简化为:配置客户端参数→初始化任务获取UploadId→分片并行上传记录序号与ETag→合并分片完成上传,新手可以先使用100MB左右的测试文件验证参数配置和流程正确性,再处理GB级以上的超大文件。如果想要降低开发成本,也可以直接选择七彩云对象存储这类完全兼容S3协议的存储服务,使用封装好的高级上传接口,无需自行实现分片逻辑,只需要几行代码即可完成大文件上传功能。开发完成后建议配置未完成分片的自动清理规则,避免不必要的存储资源浪费。
需要稳定、兼容 S3 的对象存储?
七彩云对象存储适合图片、视频、大文件下载、静态资源托管和开发者接入。
访问七彩云官网