【问题标题】:Renaming a container/folder in azure blob storage重命名 azure blob 存储中的容器/文件夹
【发布时间】:2020-03-27 01:49:42
【问题描述】:

我正在尝试在满足条件时为用户重命名容器名称。我做了一些研究,发现 azure blob 存储中的容器没有重命名功能。但是有一种方法可以通过复制文件并在复制后将其删除来完成此操作。下面是我制作的代码。

        string ContainerName = "old-container-name-user1";
        string NewContainerName = "new-container-name-user2"

        CloudStorageAccount sourceAccount = CloudStorageAccount.Parse(CloudConfigurationManager.GetSetting("StorageConnectionString"));

        CloudBlobClient sourceblobClient = sourceAccount.CreateCloudBlobClient();
        CloudBlobContainer sourceBlobContainer = sourceblobClient.GetContainerReference(ContainerName);

        CloudBlobContainer destBlobContainer = sourceblobClient.GetContainerReference(NewContainerName);

        CloudBlockBlob blobOriginal = sourceBlobContainer.GetBlockBlobReference(ContainerName);
        CloudBlockBlob blobNew = destBlobContainer.GetBlockBlobReference(NewContainerName);

        blobNew.StartCopy(blobOriginal);
        blobOriginal.Delete();

当我执行此代码时,我收到一条错误消息。以下是错误。

用户未处理的异常 Microsoft.WindowsAzure.Storage.StorageException:'远程服务器 返回错误:(404)未找到。'

Inner Exception WebException:远程服务器返回错误: (404) 未找到。

当我也尝试“blobNew.StartCopyAsync(blobOriginal)”时,代码刚刚通过,但是当我在 azure 中检查容器时,没有创建容器。你认为问题是什么?关于如何改进我的代码的任何提示?删除功能也不起作用。

更新 我更新了我的代码,并且能够将文件从其他容器复制到新容器。下面是代码。

string ContainerName = "old-container-name-user1"
string NewContainerName = "new-container-name-user2"
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(CloudConfigurationManager.GetSetting("StorageConnectionString"));
CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
CloudBlobContainer container = blobClient.GetContainerReference(ContainerName);
CloudBlobContainer destcontainer = blobClient.GetContainerReference(NewContainerName);
destcontainer.CreateIfNotExists(BlobContainerPublicAccessType.Blob);
IEnumerable<IListBlobItem> IE = container.ListBlobs(useFlatBlobListing: true);
foreach (IListBlobItem item in IE)
{
    CloudBlockBlob blob = (CloudBlockBlob)item;
    CloudBlockBlob destBlob = destcontainer.GetBlockBlobReference(blob.Name);
    destBlob.StartCopyAsync(new Uri(GetSharedAccessUri(blob.Name, container)));
}

AccessURI 方法

 private static string GetSharedAccessUri(string blobName, CloudBlobContainer container)
    {
        DateTime toDateTime = DateTime.Now.AddMinutes(60);
        SharedAccessBlobPolicy policy = new SharedAccessBlobPolicy
        {
            Permissions = SharedAccessBlobPermissions.Read,
            SharedAccessStartTime = null,
            SharedAccessExpiryTime = new DateTimeOffset(toDateTime)
        };

        CloudBlockBlob blob = container.GetBlockBlobReference(blobName);
        string sas = blob.GetSharedAccessSignature(policy);
        return blob.Uri.AbsoluteUri + sas;
    }

现在它可以工作了,但出现了另一个问题。它说

System.InvalidCastException: '无法转换类型的对象 'Microsoft.WindowsAzure.Storage.Blob.CloudBlobDirectory' 键入 'Microsoft.WindowsAzure.Storage.Blob.CloudBlockBlob'。

但这将在另一个问题中发布。感谢我们的朋友 Gauriv 指出我的问题。在下面查看他的答案。

更新 2

通过在IEnumerable&lt;IListBlobItem&gt; IE = container.ListBlobs(blobListingDetails: BlobListingDetails.Metadata); 中添加useFlatBlobListing: true,我能够解决我的问题。这行代码放在我的显示器上。

最终代码

        IEnumerable<IListBlobItem> IE = container.ListBlobs(blobListingDetails: BlobListingDetails.Metadata, useFlatBlobListing: true);

【问题讨论】:

  • StartCopy 方法会将 blob 从源容器复制到目标容器。您将容器的名称指定为 blob 名称,这就是您收到错误的原因。

标签: c# asp.net azure blob azure-blob-storage


【解决方案1】:

如果您查看用于创建源和目标 blob 的代码:

    CloudBlockBlob blobOriginal = sourceBlobContainer.GetBlockBlobReference(ContainerName);
    CloudBlockBlob blobNew = destBlobContainer.GetBlockBlobReference(NewContainerName);

您会注意到您传递的是 blob 容器的名称,而不是 blob 的名称。因为容器中没有容器名称的 blob,所以会出现 404 错误。


要复制 blob 容器,您需要列出源容器中的所有 blob,然后将它们分别复制到目标容器中。复制完所有 Blob 后,您可以删除源容器。

如果你愿意,你可以使用微软的存储资源管理器来实现“重命名容器”的功能。它还可以将 blob 从旧容器复制到重命名的容器,然后删除旧容器。


    static void RenameContainer()
    {
        var connectionString = "DefaultEndpointsProtocol=https;AccountName=account-name;AccountKey=account-key";
        var storageAccount = CloudStorageAccount.Parse(connectionString);
        var client = storageAccount.CreateCloudBlobClient();
        var sourceContainer = client.GetContainerReference("source-container");
        var targetContainer = client.GetContainerReference("target-container");
        targetContainer.CreateIfNotExists();//Create target container
        BlobContinuationToken continuationToken = null;
        do
        {
            Console.WriteLine("Listing blobs. Please wait...");
            var blobsResult = sourceContainer.ListBlobsSegmented(prefix: "", useFlatBlobListing: true, blobListingDetails: BlobListingDetails.All, maxResults: 1000, currentToken: continuationToken, options: new BlobRequestOptions(), operationContext: new OperationContext());
            continuationToken = blobsResult.ContinuationToken;
            var items = blobsResult.Results;
            foreach (var item in items)
            {
                var blob = (CloudBlob)item;
                var targetBlob = targetContainer.GetBlobReference(blob.Name);
                Console.WriteLine(string.Format("Copying \"{0}\" from \"{1}\" blob container to \"{2}\" blob container.", blob.Name, sourceContainer.Name, targetContainer.Name));

                targetBlob.StartCopy(blob.Uri);
            }
        } while (continuationToken != null);
        Console.WriteLine("Deleting source blob container. Please wait.");
        //sourceContainer.DeleteIfExists();
        Console.WriteLine("Rename container operation complete. Press any key to terminate the application.");
    }

【讨论】:

  • 感谢您的指出。现在它是有道理的。有没有办法可以使用代码更改它?一旦用户单击某个按钮,我想更改容器名称。Microsoft Storage Explorer 似乎是一个工具。 @Gaurav Mantri
  • Gaurav,我对你的代码做了一些小改动。有没有办法改变文件的元数据[“文件名”]?在某些情况下,如果上传或复制了特定文件,我想重命名文件和文件的元数据文件名。例如,这个 pdf 在执行之前被命名为“source-container.pdf”,我希望它命名为“target-container.pdf”。
  • 我在你的 foreach 条件中添加了这个。 if (blob.Metadata["Filename"].Contains("source-container")) { blob.Metadata["Filename"] = blob.Metadata["Filename"].Replace("source-container", "target-容器”); targetBlob.SetMetadata(); }
  • 问题是我更改后收到此错误。异常详细信息:System.Collections.Generic.KeyNotFoundException:字典中不存在给定的键。
  • 你能问一个单独的问题吗?请务必包含您正在使用的代码以及您遇到的问题。
【解决方案2】:

您可以使用 Microsoft 的“Microsoft Azure Storage Explorer”(版本 0.8.3 之后)重命名容器。

实际答案: 关于您的错误消息,如果客户端应用程序从服务器收到 HTTP 404(未找到)消息,这意味着客户端尝试使用的对象在存储服务中不存在。这有几个可能的原因,例如:

· 客户端或其他进程先前删除了对象(确保名称正确)

· 共享访问签名 (SAS) 授权问题

· 客户端代码无权访问对象

· 网络故障

为了详细识别问题,可以添加 try/catch 并查看实际错误

【讨论】:

  • 如果您查看错误,它是 404 错误,即未找到。另外,您在代码中的哪个位置看到使用了 SAS?您对 JS 的评论也是如此……代码是 C#。
  • 这些都是可能的原因:),谢谢纠正
  • 不,他们不是。这就是我提到它们的原因。
  • 我想知道有什么不同。我在回答中提到的同样的事情
猜你喜欢
  • 2021-05-25
  • 1970-01-01
  • 2013-04-13
  • 1970-01-01
  • 1970-01-01
  • 2016-04-03
  • 2023-03-03
  • 2022-10-20
  • 2018-11-07
相关资源
最近更新 更多