
Amazon S3 本身不支持通配符(如 x/y/*)直接删除对象,但可通过“列出前缀 + 分批删除”模式实现类似功能;本文详解如何用 Go(基于 AWS SDK for Go)安全、高效地批量删除指定前缀下的所有对象。
Amazon S3 本身不支持通配符(如 `x/y/*`)直接删除对象,但可通过“列出前缀 + 分批删除”模式实现类似功能;本文详解如何用 Go(基于 AWS SDK for Go)安全、高效地批量删除指定前缀下的所有对象。
在 Amazon S3 中,路径(如 "x/y/file.jpg")本质上是对象键(Key)的字符串,S3 并无真正的目录结构,而是通过前缀(prefix)模拟层级。因此,所谓“删除 x/y* 下的所有文件”,实际等价于:列出所有以 "x/y" 为前缀的对象键,并分批调用 DeleteObjects API 删除它们。
AWS 官方 Go SDK(即 github.com/aws/aws-sdk-go-v2)不提供开箱即用的 DeleteAllObjects 方法(与 PHP SDK 的 delete_all_objects 不同),需手动组合 ListObjectsV2 与 DeleteObjects 实现。以下是完整、健壮的实现方案:
✅ 正确做法:前缀遍历 + 分批删除(符合 S3 最佳实践)
package main
import (
"context"
"fmt"
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/config"
"github.com/aws/aws-sdk-go-v2/service/s3"
"github.com/aws/aws-sdk-go-v2/service/s3/types"
)
func deleteObjectsByPrefix(ctx context.Context, client *s3.Client, bucket, prefix string) error {
var keysToDelete []types.ObjectIdentifier
// Step 1: 列出所有匹配 prefix 的对象(支持分页)
paginator := s3.NewListObjectsV2Paginator(client, &s3.ListObjectsV2Input{
Bucket: aws.String(bucket),
Prefix: aws.String(prefix),
})
for paginator.HasMorePages() {
page, err := paginator.NextPage(ctx)
if err != nil {
return fmt.Errorf("failed to list objects: %w", err)
}
for _, obj := range page.Contents {
keysToDelete = append(keysToDelete, types.ObjectIdentifier{
Key: obj.Key,
})
}
}
if len(keysToDelete) == 0 {
fmt.Printf("No objects found with prefix '%s' in bucket '%s'\n", prefix, bucket)
return nil
}
// Step 2: 分批删除(S3 每次最多接受 1000 个对象)
const maxBatchSize = 1000
for i := 0; i < len(keysToDelete); i += maxBatchSize {
end := i + maxBatchSize
if end > len(keysToDelete) {
end = len(keysToDelete)
}
batch := keysToDelete[i:end]
_, err := client.DeleteObjects(ctx, &s3.DeleteObjectsInput{
Bucket: aws.String(bucket),
Delete: &types.Delete{
Objects: batch,
Quiet: aws.Bool(true), // 减少响应体积(仅返回失败项)
},
})
if err != nil {
return fmt.Errorf("failed to delete batch [%d-%d]: %w", i, end-1, err)
}
fmt.Printf("Deleted %d objects (batch %d–%d)\n", len(batch), i, end-1)
}
fmt.Printf("✅ Successfully deleted %d objects under prefix '%s'\n", len(keysToDelete), prefix)
return nil
}
// 使用示例
func main() {
ctx := context.Background()
cfg, err := config.LoadDefaultConfig(ctx)
if err != nil {
panic("failed to load AWS config: " + err.Error())
}
client := s3.NewFromConfig(cfg)
err = deleteObjectsByPrefix(ctx, client, "my-bucket", "x/y/")
if err != nil {
panic(err)
}
}⚠️ 关键注意事项
- 前缀非正则表达式:"x/y/" 是纯字符串前缀匹配(等效于 Key.StartsWith("x/y/")),不是通配符或 PCRE。若需更复杂匹配(如 x/y/*.log),须在 ListObjectsV2 后用 Go 的 filepath.Match 或正则进行客户端过滤。
- 分页必须处理:S3 列表结果默认最多 1000 条,务必使用 ListObjectsV2Paginator 遍历全部页面,否则会遗漏对象。
- 删除上限:DeleteObjects 单次最多删除 1000 个对象,代码中已按 maxBatchSize=1000 自动切片。
- 错误处理:DeleteObjects 返回的 Errors 字段仅包含失败项,建议检查并重试(本例为简化未展开);生产环境应加入重试逻辑与日志审计。
- 权限要求:IAM 策略需同时授予 s3:ListBucket(用于 ListObjectsV2)和 s3:DeleteObject(用于 DeleteObjects)权限。
? 总结
虽然 Go SDK 没有内置 DeleteAllObjects,但通过组合 ListObjectsV2Paginator 与分批 DeleteObjects,即可安全、可扩展地实现前缀级批量清理。该模式完全遵循 AWS API 设计规范,适用于任意规模存储桶(百万级对象亦可稳定运行)。建议将其封装为通用工具函数,复用于日志归档清理、测试数据重置等场景。