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

I have the following working code to delete an object from Amazon s3

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

But what i want to do is to delete all files under a folder using wildcard **. I know amazon s3 doesn't treat "x/y/file.jpg" as a folder y inside x but what i want to achieve is by mentioning "x/y*" delete all the subsequent objects having the same prefix. Tried amazon multi object delete

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

I know in php it can be done easily by s3->delete_all_objects as per this answer. Is the same action possible in GOlang.

Unfortunately the goamz package doesn't have a method similar to the PHP library's delete_all_objects.

However, the source code for the PHP delete_all_objects is available here (toggle source view): http://docs.aws.amazon.com/AWSSDKforPHP/latest/#m=AmazonS3/delete_all_objects

Here are the important lines of code:

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();

As you can see, the PHP code will actually make an HTTP request on the bucket to first get all files matching PCRE_ALL, which is defined elsewhere as const PCRE_ALL = '/.*/i';.

You can only delete 1000 files at once, so delete_all_objects then creates a batch function to delete 1000 files at a time.

You have to create the same functionality in your go program as the goamz package doesn't support this yet. Luckily it should only be a few lines of code, and you have a guide from the PHP library.

It might be worth submitting a pull request for the goamz package once you're done!

Using the mc tool you can do:

mc rm -r --force https://BucketName.s3.amazonaws.com/x/y

it will delete all the objects with the prefix "x/y"

You can achieve the same with Go using minio-go like this:

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)
    }
}

A bit late in the game, but since I was having the same problem, I created a small pkg that you can copy to your code base and import as needed.

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
}

So, in the case you have a bucket called "somebucket" with the following structure: s3://somebucket/foo/some-prefixed-folder/bar/test.txt and wanted to delete from some-prefixed-folder onwards, usage would be:

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

This implementation only allows to delete a maximum of 1000 entries from the given prefix due ListObjectsV2 implementation - but it is paginated, so it's a matter of adding the functionality to keep refreshing results until results are < 1000.

都是prefix ...,可以使用正则匹配么,比如我想要删除key中包含某个字符串的所有对象,如果以前缀匹配太easy了