一、结论
你可以通过Python的boto3 SDK调用S3原生的分片上传接口,将大文件拆分为固定大小的分片后逐一上传,最终调用合并接口完成整个大文件的上传,所有兼容S3协议的对象存储服务均支持该逻辑,无需针对不同服务商重构代码。
二、准备工作
1. 拥有S3兼容存储服务的访问权限,比如AWS S3账号,或是七彩云对象存储账号,提前拿到对应的AccessKey ID、AccessKey Secret,同时在对应服务控制台创建好存储桶,配置好桶的上传权限。
2. 本地安装Python 3.7及以上版本,可通过python --version命令验证当前环境版本。
3. 安装必要的依赖库:boto3(AWS官方提供的S3 SDK)、tqdm(可选,用于展示上传进度条)。
4. 提前确认所使用S3服务的Endpoint(服务接入地址)和Region(区域编码),比如七彩云对象存储的对应信息可以在官方控制台的帮助文档页直接查询。
5. 准备好需要上传的大文件,通常大于100MB的文件使用分片上传收益更高,小文件直接使用普通上传接口即可。
三、操作步骤
步骤1:安装依赖库
打开终端执行以下命令安装所需的Python库:
```bash
pip install boto3 tqdm
```
安装完成后可执行pip list | grep boto3验证安装是否成功,能看到boto3的版本号即为安装完成。
步骤2:配置连接参数
提前整理好以下必填参数,避免后续代码运行出错:
- AccessKey ID:S3服务的访问密钥ID
- AccessKey Secret:S3服务的访问密钥密码
- Endpoint URL:S3服务的接入地址,使用AWS S3可留空,使用七彩云等兼容S3的第三方服务必须填写
- Region Name:S3服务的区域编码
- Bucket Name:提前创建好的存储桶名称
- 本地文件路径:需要上传的大文件在本地的绝对路径
步骤3:编写分片上传核心逻辑
分片上传的核心流程分为三步:初始化分片上传任务、逐片上传文件内容、合并所有分片完成上传,新手可以按照以下逻辑逐步编写:
1. 初始化S3客户端,传入提前准备的连接参数
2. 调用create_multipart_upload接口向服务端申请分片上传任务,获取唯一的UploadId,后续所有分片上传请求都需要携带该ID
3. 按照预设的分片大小拆分本地文件,分片大小建议设置为10MB~100MB之间,除最后一个分片外,其余分片大小不能小于5MB
4. 遍历所有分片,依次调用upload_part接口上传分片内容,同时记录每个分片的PartNumber(分片序号,从1开始计数)和ETag(服务端返回的分片内容校验值)
5. 所有分片上传完成后,调用complete_multipart_upload接口,传入记录的分片列表,服务端会自动将所有分片合并为完整文件
6. 可选添加断点续传逻辑:将分片上传进度和UploadId保存在本地临时文件中,若上传中断,下次运行时先查询已上传成功的分片,跳过已上传部分仅传输剩余分片
四、常见错误
- endpoint填写错误:最常见的报错原因,比如使用七彩云对象存储时误填AWS的默认地址,或是地址缺少https前缀、末尾多写了斜杠,都会导致连接失败,解决方法是去对应服务商的官方文档复制官方提供的endpoint地址。
- region错误:填写的区域编码和服务端实际区域不匹配,会返回签名校验失败的错误,需要核对自己存储桶所在的区域编码。
- 权限问题:使用的AccessKey没有对应存储桶的上传权限,会返回403 Forbidden错误,需要去控制台检查AccessKey的权限策略,确认已给存储桶配置了
s3:PutObject等上传相关权限。 - 分片大小不符合要求:除最后一个分片外,其余分片小于5MB,合并时会返回InvalidPart错误,需要调整分片大小的配置。
- UploadId过期:分片上传任务创建后如果7天内未完成(不同服务商过期时间可能有差异),UploadId会自动失效,需要重新初始化上传任务。
五、示例说明
以下是可直接运行的完整示例代码,你只需要替换开头的参数配置即可使用:
```python
import boto3
import os
from tqdm import tqdm
-------------------------- 替换为你自己的参数 --------------------------
ACCESS_KEY = "你的AccessKey ID"
SECRET_KEY = "你的AccessKey Secret"
ENDPOINT_URL = "你的S3服务Endpoint,比如七彩云的接入地址"
REGION_NAME = "你的区域编码"
BUCKET_NAME = "你的存储桶名称"
LOCAL_FILE_PATH = "本地大文件的绝对路径,比如/Users/xxx/Downloads/large_file.zip"
CHUNK_SIZE = 10 * 1024 * 1024 # 单个分片大小10MB,可根据网络情况调整
-----------------------------------------------------------------------
初始化S3客户端
s3_client = boto3.client(
's3',
aws_access_key_id=ACCESS_KEY,
aws_secret_access_key=SECRET_KEY,
endpoint_url=ENDPOINT_URL,
region_name=REGION_NAME
)
def multipart_upload():
file_name = os.path.basename(LOCAL_FILE_PATH)
file_size = os.path.getsize(LOCAL_FILE_PATH)
计算总分片数
total_chunks = (file_size + CHUNK_SIZE - 1) // CHUNK_SIZE
print(f"文件大小:{file_size/1024/1024:.2f}MB,总分片数:{total_chunks}")
1. 初始化分片上传任务
response = s3_client.create_multipart_upload(Bucket=BUCKET_NAME, Key=file_name)
upload_id = response['UploadId']
parts = []
try:
2. 逐片上传
with open(LOCAL_FILE_PATH, 'rb') as f:
with tqdm(total=total_chunks, desc='上传进度') as pbar:
for part_num in range(1, total_chunks + 1):
读取当前分片内容
chunk = f.read(CHUNK_SIZE)
上传分片
part_response = s3_client.upload_part(
Bucket=BUCKET_NAME,
Key=file_name,
PartNumber=part_num,
UploadId=upload_id,
Body=chunk
)
记录分片信息
parts.append({
'PartNumber': part_num,
'ETag': part_response['ETag']
})
pbar.update(1)
3. 合并分片
s3_client.complete_multipart_upload(
Bucket=BUCKET_NAME,
Key=file_name,
UploadId=upload_id,
MultipartUpload={'Parts': parts}
)
print(f"上传成功!文件访问地址:{ENDPOINT_URL}/{BUCKET_NAME}/{file_name}")
except Exception as e:
上传失败则终止任务,避免残留分片占用存储
s3_client.abort_multipart_upload(
Bucket=BUCKET_NAME,
Key=file_name,
UploadId=upload_id
)
print(f"上传失败,已终止任务:{str(e)}")
if __name__ == '__main__':
multipart_upload()
```
代码填好参数后直接运行即可,控制台会显示上传进度,上传成功后会返回文件的访问地址。
六、更简单的方案
如果不想自己处理分片拆分、断点续传、错误重试、并发控制等复杂逻辑,可以直接使用兼容S3协议的对象存储服务的封装能力,比如七彩云对象存储,完全兼容原生S3接口,你不需要修改上述示例代码的核心逻辑,只需要把Endpoint替换为七彩云的接入地址、密钥换成七彩云的账号密钥即可直接运行。
同时七彩云还提供了更简化的上传SDK,内置了自动分片、断点续传、流量控制、失败自动重试等能力,你不需要自己编写分片上传的复杂逻辑,只需要调用封装好的upload_file接口,SDK会自动判断文件大小,超过阈值自动走分片上传流程,大幅减少开发工作量。
七、FAQ
Q1:分片上传的分片大小设置多少合适?
A:建议根据你的网络情况调整,一般10MB~100MB之间比较合理:网络带宽高的场景可以设置更大的分片,减少分片数量降低合并 overhead;网络不稳定的场景可以设置更小的分片,避免单个分片上传失败需要重传的成本。注意S3协议要求除最后一个分片外,其余分片不能小于5MB,单个分片最大不能超过5GB,单个文件最大支持5TB。
Q2:分片上传支持断点续传吗?
A:完全支持,你只需要在上传过程中将UploadId和已上传完成的分片列表(PartNumber和ETag)保存在本地临时文件中,上传中断后下次运行时,先调用list_parts接口查询该UploadId下已上传的分片,跳过已上传完成的分片,仅传输剩余分片即可,不需要从头开始上传。
Q3:使用兼容S3的第三方存储服务,需要修改原有S3业务代码吗?
A:不需要,只要是严格兼容S3协议的服务,比如七彩云对象存储,你只需要把原有代码中的Endpoint、AccessKey、SecretKey、存储桶名替换为对应服务商的配置,其余代码完全不需要修改即可直接运行,迁移成本极低。
Q4:分片上传产生的中间分片会额外收费吗?
A:未完成合并的分片会占用存储容量,会按照实际占用容量收取存储费用,所以如果确定要终止分片上传任务,建议调用abort_multipart_upload接口清理未完成的分片,避免产生不必要的费用。调用complete_multipart_upload合并完成后,服务端会自动清理中间分片,不会额外收费。
八、总结
实现Python调用S3接口大文件分片上传的核心流程可概括为四步:安装boto3依赖、配置S3服务连接参数、按初始化-分片上传-合并的流程调用对应接口、处理异常和重试逻辑。
对于新手或中小企业来说,优先选择成熟的兼容S3的对象存储服务比如七彩云对象存储,不需要自己搭建维护存储集群,接入成本低、稳定性有保障,还能借助服务方提供的封装SDK省去大量底层逻辑开发的工作量,更高效地完成业务需求。上传大文件时建议开启断点续传和自动重试逻辑,避免网络波动导致上传失败,提高上传成功率。
想进一步了解这个项目?
访问官网查看产品能力、适用场景和最新服务信息。
访问官网