
当 S3 对象超过 5 GB 时,无法直接使用 CopyObject 或单次 UploadPartCopy 完成重命名;必须结合 CreateMultipartUpload 与带 CopySourceRange 的多次 UploadPartCopy 手动分段复制。
当 s3 对象超过 5 gb 时,无法直接使用 `copyobject` 或单次 `uploadpartcopy` 完成重命名;必须结合 `createmultipartupload` 与带 `copysourcerange` 的多次 `uploadpartcopy` 手动分段复制。
在 AWS S3 中,重命名本质上是复制 + 删除,而标准 CopyObject API 仅支持 ≤ 5 GB 的对象。对于更大的对象(如 10 GB 日志文件),必须采用 Multi-part Copy(分段复制) 方式——但这并非自动分片,而是需要开发者显式计算字节范围并逐段发起 UploadPartCopy 请求。
关键误区澄清:
- ❌
ListPartsPages是用于查询已上传的 multipart upload 分段列表,而非源对象的结构;源对象是普通 S3 Object,无“内置分段”概念。 - ❌
UploadPartCopy不会自动切分源对象;必须手动指定CopySourceRange(如"bytes=0-9999999")来定义每段复制的字节区间。 - ✅ 正确流程:先
HEAD源对象获取ContentLength→ 创建 multipart upload → 按固定大小(如 5 MB 或 10 MB)切分范围 → 调用多次UploadPartCopy→ 最后CompleteMultipartUpload。
以下是完整、健壮的 Go 实现示例(使用 AWS SDK for Go v1):
func copyS3ObjectWithMultipart(
svc *s3.S3,
bucket, sourceKey, targetKey string,
partSize int64, // 推荐 ≥ 5 MB(S3 最小分段要求)
) error {
// 1. 获取源对象大小
headResp, err := svc.HeadObject(&s3.HeadObjectInput{
Bucket: aws.String(bucket),
Key: aws.String(sourceKey),
})
if err != nil {
return fmt.Errorf("failed to head source object: %w", err)
}
totalSize := *headResp.ContentLength
// 2. 创建 Multipart Upload
createResp, err := svc.CreateMultipartUpload(&s3.CreateMultipartUploadInput{
Bucket: aws.String(bucket),
Key: aws.String(targetKey),
})
if err != nil {
return fmt.Errorf("failed to create multipart upload: %w", err)
}
uploadID := *createResp.UploadId
// 3. 分段复制:计算 range 并逐段上传
var completedParts []*s3.CompletedPart
for start := int64(0); start < totalSize; start += partSize {
end := start + partSize - 1
if end >= totalSize {
end = totalSize - 1
}
rangeStr := fmt.Sprintf("bytes=%d-%d", start, end)
partNum := int64(len(completedParts) + 1)
resp, err := svc.UploadPartCopy(&s3.UploadPartCopyInput{
Bucket: aws.String(bucket),
Key: aws.String(targetKey),
UploadId: aws.String(uploadID),
PartNumber: aws.Int64(partNum),
CopySource: aws.String(fmt.Sprintf("%s/%s", bucket, sourceKey)),
CopySourceRange: aws.String(rangeStr),
})
if err != nil {
// 清理已创建的 upload 避免残留
svc.AbortMultipartUpload(&s3.AbortMultipartUploadInput{
Bucket: aws.String(bucket),
Key: aws.String(targetKey),
UploadId: aws.String(uploadID),
})
return fmt.Errorf("failed to upload part %d (%s): %w", partNum, rangeStr, err)
}
completedParts = append(completedParts, &s3.CompletedPart{
ETag: resp.CopyPartResult.ETag,
PartNumber: aws.Int64(partNum),
})
}
// 4. 完成分段上传
_, err = svc.CompleteMultipartUpload(&s3.CompleteMultipartUploadInput{
Bucket: aws.String(bucket),
Key: aws.String(targetKey),
UploadId: aws.String(uploadID),
MultipartUpload: &s3.CompletedMultipartUpload{
Parts: completedParts,
},
})
if err != nil {
svc.AbortMultipartUpload(&s3.AbortMultipartUploadInput{
Bucket: aws.String(bucket),
Key: aws.String(targetKey),
UploadId: aws.String(uploadID),
})
return fmt.Errorf("failed to complete multipart upload: %w", err)
}
return nil
}✅ 最佳实践与注意事项:
- 分段大小:最小为 5 MB(除最后一段外),建议统一设为 8–16 MB 以平衡并发与内存开销;避免过小导致请求激增。
-
CopySource 格式:必须为
"{bucket}/{key}"(URL 编码需谨慎,SDK 通常自动处理)。 -
ETag 验证:
UploadPartCopy返回的ETag必须原样传入CompleteMultipartUpload,不可修改或解码。 -
错误恢复:生产环境应加入幂等性设计(如用唯一 upload ID 关联任务)、断点续传逻辑及失败自动清理(
AbortMultipartUpload)。 -
权限要求:确保 IAM 策略同时允许
s3:GetObject(源桶)、s3:PutObject和s3:ListMultipartUploadParts(目标桶)。
通过该方案,你不仅能安全重命名任意大小的 S3 对象,还为后续实现批量重命名、跨区域复制、条件迁移等高级场景打下坚实基础。

















