如何使用AmazonS3.net sdk重命名存储桶中的文件夹

时间:2011-12-06 06:39:13

标签: .net c amazon-s3

我知道s3并不真正支持文件夹概念。复制/删除所有文件应该工作。但也许有人知道一种更简单的方法(而且我还没有在SDK中找到它)

更新/解决方案:

以下代码对我有用。

       using (AmazonS3 client = Amazon.AWSClientFactory.CreateAmazonS3Client("xxx",
                                                              "yyy"))
        {

            ListObjectsRequest listRequest = new ListObjectsRequest();
            listRequest.WithBucketName("ytimusic")
                .WithPrefix("M" + oldOWnerId.ToString()+"/");


            // get all objects inside the "folder"
            ListObjectsResponse objects = client.ListObjects(listRequest);
            foreach (S3Object s3o in objects.S3Objects)
            {

                // get the acl of the object
                GetACLRequest aclRequest = new GetACLRequest();
                aclRequest.WithBucketName("thebucket")
                    .WithKey(s3o.Key);
                GetACLResponse getAclResponse = client.GetACL(aclRequest);


                // copy the object without acl
                string newKey = s3o.Key.Replace(oldOWnerId.ToString(), newOwnerId.ToString());
                CopyObjectRequest copyRequest = new CopyObjectRequest();
                copyRequest.SourceBucket = "thebucket";
                copyRequest.DestinationBucket = "thebucket";
                copyRequest.WithSourceKey(s3o.Key)
                .WithDestinationKey(newKey);
                S3Response copyResponse = client.CopyObject(copyRequest);

                // set the acl of the newly created object
                SetACLRequest setAclRequest = new SetACLRequest();
                setAclRequest.WithBucketName("ytimusic")
                    .WithKey(newKey)
                    .WithACL(getAclResponse.AccessControlList);

                SetACLResponse setAclRespone = client.SetACL(setAclRequest);

                DeleteObjectRequest deleteRequest = new DeleteObjectRequest();
                deleteRequest.WithBucketName("thebucket")
                    .WithKey(s3o.Key);

                DeleteObjectResponse deleteResponse = client.DeleteObject(deleteRequest);

            }
        }

3 个答案:

答案 0 :(得分:4)

ListObjectResponse默认只返回1000个对象。如果有超过1000个对象,则.IsTruncated属性设置为true。您可以更改ListObjectsRequest标记以获取下一个1000个对象。因此,如果重命名操作可能会影响超过1000个对象,则可以使用以下代码。

public void MoveDirectory(string sourceKey, string destinationKey)
    {

        //Find all keys with a prefex of sourceKey, and rename them with destinationKey for prefix
        try
        {
            DeleteObjectsRequest deleteObjectsRequest = new DeleteObjectsRequest() {
                BucketName = bucket
            };
            ListObjectsRequest listObjectsRequest = new ListObjectsRequest {
                BucketName = bucket,
                Prefix = sourceKey,
            };
            do
            {
                ListObjectsResponse listObjectsResponse = client.ListObjects(listObjectsRequest);
                foreach (var s3Object in listObjectsResponse.S3Objects)
                {
                    string newKey = s3Object.Key.Replace(sourceKey, destinationKey);

                    CopyObjectRequest copyObjectRequest = new CopyObjectRequest() {
                        SourceBucket = bucket,
                        DestinationBucket = bucket,
                        SourceKey = s3Object.Key,
                        DestinationKey = newKey
                    };

                    CopyObjectResponse copyObectResponse = client.CopyObject(copyObjectRequest);
                    deleteObjectsRequest.AddKey(s3Object.Key);
                }
                if (listObjectsResponse.IsTruncated)
                {
                    listObjectsRequest.Marker = listObjectsResponse.NextMarker;
                }
                else
                {
                    listObjectsRequest = null;
                }

            } while (listObjectsRequest != null);

            client.DeleteObjects(deleteObjectsRequest);
        }
        catch (AmazonS3Exception amazonS3Exception)
        {
            Logger.Error("Error Occured with S3 MOVE", amazonS3Exception);
        }
    }

答案 1 :(得分:3)

S3既不支持重命名也不支持文件夹,因此您实际上需要通过创建具有所需名称的副本并删除原始文件来单独处理每个文件。要使用.NET SDK执行此操作,我担心没有比列出目录中的所有文件更简单的方法,并使用CopyObject + DeleteObject重命名每个文件。另外,请注意,根据文档(http://docs.amazonwebservices.com/AmazonS3/latest/API/index.html?RESTObjectCOPY.html),复制操作不会保留ACL,因此如果移动的文件是公开的你需要明确地将副本标记为公开。

答案 2 :(得分:3)

我能看到的唯一能让这段代码变得更好的方法就是批量删除请求并一次性将其关闭。

        ListObjectsRequest listRequest = new ListObjectsRequest();
        listRequest.WithBucketName(_bucket).WithPrefix(oldPath);

        DeleteObjectsRequest deleteRequest = new DeleteObjectsRequest();
        deleteRequest.WithBucketName(_bucket);

        // GET ALL OBJECTS UNDER THIS "FOLDER" AND LOOP OVER THEM
        ListObjectsResponse listResponse = _client.ListObjects(listRequest);
        foreach (var obj in listResponse.S3Objects)
        {
            // GET THE ACCESS CONTROL LIST FROM THIS OBJECT BECAUSE COPY PROCEDURES DONT TAKE THIS INTO ACCOUNT
            GetACLRequest aclRequest = new GetACLRequest();
            aclRequest.WithBucketName(_bucket).WithKey(obj.Key);
            GetACLResponse aclResponse = _client.GetACL(aclRequest);

            // GET THE NEW KEY AND COPY THIS OBJECT TO IT
            String newKey = obj.Key.Replace(oldPath, newPath);
            CopyObjectRequest copyRequest = new CopyObjectRequest { SourceBucket = _bucket, DestinationBucket = _bucket };
            copyRequest.WithSourceKey(obj.Key).WithDestinationKey(newKey);
            CopyObjectResponse copyResponse = _client.CopyObject(copyRequest);

            // COPY OVER THE ACCESS CONTROL LIST TO THIS "NEW" OBJECT
            SetACLRequest setAclRequest = new SetACLRequest();
            setAclRequest.WithBucketName(_bucket).WithKey(newKey).WithACL(aclResponse.AccessControlList);
            SetACLResponse setAclResponse = _client.SetACL(setAclRequest);

            // ADD THE OLD ITEM TO THE DELETE REQUEST
            deleteRequest.AddKey(obj.Key);
        }

        // DELETE ALL THE OLD OBJECTS IN ONE SHOT TO SAVE ON TRIPS BACK AND FORTH
        _client.DeleteObjects(deleteRequest);