Go语言 使用通配符匹配删除s3中的对象

20jt8wwn  于 2023-05-11  发布在  Go
关注(0)|答案(5)|浏览(169)

我有下面的工作代码来从Amazons 3中删除对象

params := &s3.DeleteObjectInput{
        Bucket: aws.String("Bucketname"),
        Key : aws.String("ObjectKey"),
    }
s3Conn.DeleteObjects(params)

但我想做的是删除所有文件夹下使用通配符**。我知道amazon s3没有把“x/y/file.jpg”当作x里面的一个文件夹y,但是我想实现的是通过提到“x/y*”删除所有具有相同前缀的后续对象。尝试亚马逊多对象删除

params := &s3.DeleteObjectsInput{
        Bucket: aws.String("BucketName"),
        Delete: &s3.Delete{
            Objects: []*s3.ObjectIdentifier {
                {
                    Key : aws.String("x/y/.*"), 
                },
            },
        },
    }
    result , err := s3Conn.DeleteObjects(params)

我知道在php中可以很容易地通过 s3->delete_all_objects 按照this answer来完成。在GOlang中是否可以执行相同的操作。

hlswsv35

hlswsv351#

不幸的是,goamz包没有类似于PHP库的delete_all_objects的方法。
但是,PHP delete_all_objects的源代码可以在这里获得(切换源代码视图):http://docs.aws.amazon.com/AWSSDKforPHP/latest/#m=AmazonS3/delete_all_objects
以下是重要的代码行:

public function delete_all_objects($bucket, $pcre = self::PCRE_ALL)
{
// Collect all matches
    $list = $this->get_object_list($bucket, array('pcre' => $pcre));

    // As long as we have at least one match...
    if (count($list) > 0)
    {
        $objects = array();

        foreach ($list as $object)
        {
            $objects[] = array('key' => $object);
        }

        $batch = new CFBatchRequest();
        $batch->use_credentials($this->credentials);

        foreach (array_chunk($objects, 1000) as $object_set)
        {
            $this->batch($batch)->delete_objects($bucket, array(
                'objects' => $object_set
            ));
        }

        $responses = $this->batch($batch)->send();

如您所见,PHP代码实际上会在存储桶上发出一个HTTP请求,首先获取所有匹配PCRE_ALL的文件,在其他地方定义为const PCRE_ALL = '/.*/i';
您一次只能删除1000个文件,因此delete_all_objects创建了一个批处理函数来一次删除1000个文件。
你必须在你的go程序中创建相同的功能,因为goamz包还不支持这个。幸运的是,它应该只有几行代码,并且您可以从PHP库中获得指南。
完成后,提交一个goamz包的pull request可能是值得的!

n7taea2i

n7taea2i2#

使用mc工具,您可以执行以下操作:
mc rm -r --force https://BucketName.s3.amazonaws.com/x/y
它将删除所有前缀为“x/y”的对象
你可以用minio-go来实现同样的功能:

package main

import (
    "log"

    "github.com/minio/minio-go"
)

func main() {
    config := minio.Config{
        AccessKeyID:     "YOUR-ACCESS-KEY-HERE",
        SecretAccessKey: "YOUR-PASSWORD-HERE",
        Endpoint:        "https://s3.amazonaws.com",
    }
    // find Your S3 endpoint here http://docs.aws.amazon.com/general/latest/gr/rande.html

    s3Client, err := minio.New(config)
    if err != nil {
        log.Fatalln(err)
    }
    isRecursive := true
    for object := range s3Client.ListObjects("BucketName", "x/y", isRecursive) {
        if object.Err != nil {
            log.Fatalln(object.Err)
        }
        err := s3Client.RemoveObject("BucketName", object.Key)
        if err != nil {
            log.Fatalln(err)
            continue
        }
        log.Println("Removed : " + object.Key)
    }
}
neekobn8

neekobn83#

自从提出这个问题以来,S3的AWS GoLang库在S3 Manager中接收了一些新方法来处理此任务(响应@Itachi的pr)。
参见Github记录:https://github.com/aws/aws-sdk-go/issues/448#issuecomment-309078450
以下是v1中的示例:https://github.com/awsdocs/aws-doc-sdk-examples/blob/main/go/s3/DeleteObjects/DeleteObjects.go#L36
要在bucket内的路径上获得“通配符匹配”,请将Prefix参数添加到示例的ListObjectsInput调用中,如下所示:

iter := s3manager.NewDeleteListIterator(svc, &s3.ListObjectsInput{
        Bucket: bucket,
        Prefix: aws.String("somePathString"),
    })
oyxsuwqo

oyxsuwqo4#

在游戏中有点晚了,但因为我有同样的问题,我创建了一个小的pkg,您可以复制到您的代码库并根据需要导入。

func ListKeysInPrefix(s s3iface.S3API, bucket, prefix string) ([]string, error) {
    res, err := s.Client.ListObjectsV2(&s3.ListObjectsV2Input{
        Bucket: aws.String(bucket),
        Prefix: aws.String(prefix),
    })
    if err != nil {
        return []string{}, err
    }

    var keys []string
    for _, key := range res.Contents {
        keys = append(keys, *key.Key)
    }
    return keys, nil
}

func createDeleteObjectsInput(keys []string) *s3.Delete {
    rm := []*s3.ObjectIdentifier{}
    for _, key := range keys {
        rm = append(rm, &s3.ObjectIdentifier{Key: aws.String(key)})
    }
    return &s3.Delete{Objects: rm, Quiet: aws.Bool(false)}
}

func DeletePrefix(s s3iface.S3API, bucket, prefix string) error {
    keys, err := s.ListKeysInPrefix(bucket, prefix)
    if err != nil {
        panic(err)
    }

    _, err = s.Client.DeleteObjects(&s3.DeleteObjectsInput{
        Bucket: aws.String(bucket),
        Delete: s.createDeleteObjectsInput(keys),
    })

    if err != nil {
        return err
    }
    return nil
}

因此,如果您有一个名为“somebucket”的桶,其结构如下:s3://somebucket/foo/some-prefixed-folder/bar/test.txt并希望从some-prefixed-folder开始删除,则用法如下:

func main() {
    // create your s3 client here
    // client := ....
    err := DeletePrefix(client, "somebucket", "some-prefixed-folder")
    if err != nil {
        panic(err)
    }
}

由于ListObjectsV2的实现,这个实现只允许从给定的前缀中删除最多1000个条目--但是它是分页的,所以需要添加功能来不断刷新结果,直到结果< 1000。

wfveoks0

wfveoks05#

我能够使用CLI中的通配符删除S3存储桶中的对象

aws s3 rm s3://<xyz bucket name>/2023/ --recursive --exclude '*' --include 'A*.csv'

相关问题