【问题标题】:How to delete a folder within an Azure blob container如何删除 Azure Blob 容器中的文件夹
【发布时间】:2016-04-16 03:12:16
【问题描述】:

我在 Azure 中有一个名为 pictures 的 blob 容器,其中包含各种文件夹(请参见下面的快照):

我正在尝试删除快照中显示的标题为 usersuploads 的文件夹,但我保留了错误:Failed to delete blob pictures/uploads/. Error: The specified blob does not exist. 有人能说明我如何删除这两个文件夹吗?通过谷歌搜索此问题,我无法发现任何有意义的信息。

注意:如果需要,请向我询问更多信息

【问题讨论】:

标签: azure azure-storage azure-blob-storage


【解决方案1】:

这是因为“文件夹”实际上并不存在。在 Azure 存储帐户中,您拥有填充有 blob 的容器。您所看到的客户端可视化为“文件夹”的是帐户“图片/上传/”中 blob 的文件名。如果要删除“文件夹”,实际上必须删除每个以相同“路径”命名的 blob。

最常见的方法是获取这些 blob 的列表,然后将其提供给 delete blob 调用。

【讨论】:

  • 好的,但是删除 blob 调用是否可以扩展到例如 20M 个对象?
  • “规模”是一个相对术语。你能删除所有 20M 的 blob 吗?是的,你能在 1 秒内完成吗?不。您将受到 Storage API 限制的限制。
  • 把复选框“全选”也无妨
【解决方案2】:

Windows Azure Blob 存储没有文件夹的概念。层次结构非常简单:存储帐户 > 容器 > blob。实际上,删除特定文件夹就是删除所有以该文件夹名称开头的 blob。您可以编写如下简单代码来删除您的文件夹:

CloudStorageAccount storageAccount = CloudStorageAccount.Parse("your storage account");
CloudBlobContainer container = storageAccount.CreateCloudBlobClient().GetContainerReference("pictures");
foreach (IListBlobItem blob in container.GetDirectoryReference("users").ListBlobs(true))
{
    if (blob.GetType() == typeof(CloudBlob) || blob.GetType().BaseType == typeof(CloudBlob))
    {
        ((CloudBlob)blob).DeleteIfExists();
    }
}

container.GetDirectoryReference("users").ListBlobs(true) 列出“图片”容器中以“用户”开头的 blob,然后您可以单独删除它们。要删除其他文件夹,您只需要像这样指定 GetDirectoryReference("your folder name")。

【讨论】:

  • 确实如此。删除文件夹内的 blob 也会删除该文件夹。我们只需要删除文件夹中的所有 blob。
  • 在 ForEach 中你可以使用 CloudBlockBlob 代替 IListBlobItem
  • foreach (var item in items.OfType()) { item.Delete(); }
  • 它还会删除一个文件夹,比如users2 吗?
  • 对于那些使用Azure.Storage.Blobs v12 寻找最新(截至 2021 年)的用户,请查看下面@Melih 的其他答案:stackoverflow.com/a/63846242/5101
【解决方案3】:

还有一个来自 Microsoft 的桌面存储浏览器。它有一个功能,您可以选择虚拟文件夹,然后将其删除,从而有效地删除所有子 blob。

https://azure.microsoft.com/en-us/features/storage-explorer/

【讨论】:

  • 这确实从点击/脚本中保存,但在内部使用相同的枚举然后删除的机制。所以它可能会轰炸很多删除操作并且很慢,。
【解决方案4】:

让我们从一个如何使用 ListBlobsSegmentedAsyc 删除“文件夹”的示例开始:

var container = // get container reference
var ctoken = new BlobContinuationToken();
do
{
    var result = await container.ListBlobsSegmentedAsync("myfolder", true, BlobListingDetails.None, null, ctoken, null, null);
    ctoken = result.ContinuationToken;
    await Task.WhenAll(result.Results
        .Select(item => (item as CloudBlob)?.DeleteIfExistsAsync())
        .Where(task => task != null)
    );
} while (ctoken != null);

它的作用...

var ctoken = new BlobContinuationToken();

一个“文件夹”可能包含很多文件。 ListBlobSegmentedAsyc 可能只返回其中的一部分。此令牌将存储信息,以便在下次通话中继续。

var result = await container.ListBlobsSegmentedAsync("myfolder", true, BlobListingDetails.None, null, ctoken, null, null);
  • 第一个参数是所需的 blob 名称(“路径”)前缀。
  • 第二个参数“useFlatBlobListing=true”告诉客户端返回所有子文件夹中的所有项目。如果设置为 false,它将以“虚拟文件夹”模式运行,并像文件系统一样运行。
  • ctoken 将告诉 azure 在哪里继续

有关所有参数,请参阅https://docs.microsoft.com/en-us/dotnet/api/microsoft.windowsazure.storage.blob.cloudblobclient.listblobssegmentedasync?view=azure-dotnet 了解详情。

(item as CloudBlob)?.DeleteIfExistsAsync()

现在我们在 result.Results 中有一个 IListBlobItem 列表。因为不能保证 IListBlobItem 是可删除的 CloudBlob(例如,如果我们设置 useFlatBlobListing=false,它可能是一个虚拟文件夹),我们会尝试强制转换它并在可能的情况下将其删除。

result.Results.Select(item => (item as CloudBlob)?.DeleteIfExistsAsync())

触发删除所有结果并返回任务列表。

.Where(task => task != null)

如果结果包含我们无法转换为 CloudBlob 的项目,我们的任务列表包含空值。我们必须删除它们。

...然后我们等待当前段的所有删除完成并继续下一个段(如果可用)。

【讨论】:

    【解决方案5】:

    现在您可以使用生命周期管理来删除带有前缀匹配和操作的文件 删除属性daysAfterModificationGreaterThan。让规则保持活动状态约 24 小时。它会完成这项工作。 https://docs.microsoft.com/en-us/azure/storage/blobs/storage-lifecycle-management-concepts

    提供生命周期管理文档

    【讨论】:

      【解决方案6】:

      您现在可以使用 ADF 中的删除活动来删除任何文件 /blob。它会删除里面的所有文件

      【讨论】:

        【解决方案7】:

        你也可以在 Azure 云 shell 中进行;这是命令:

        az storage blob delete-batch --source <blob-container> --account-name <blob-account> --pattern <folder-name>*
        

        【讨论】:

          【解决方案8】:

          在最新的存储库 Azure.Storage.Blobs 中,它非常简单

          var connectionString = "blob-connection-string";
          var containerName = "container-name";
          var folderPath = "folder1/subfolder/sub-subfolder";
          
          var blobServiceClient = new BlobServiceClient(connectionString);
          var blobContainerClient = blobServiceClient.GetBlobContainerClient(containerName);
          var blobItems = blobContainerClient.GetBlobsAsync(prefix: folderPath);
          await foreach (BlobItem blobItem in blobItems)
          {
               BlobClient blobClient = blobContainerClient.GetBlobClient(blobItem.Name);
               await blobClient.DeleteIfExistsAsync();
          }
          

          由于每个 blob 都有自己的 uri 值,您可以在查询之前设置前缀,以便它可以获取和删除具有特定 uri 的 blob。随着 blob 被删除,该文件夹将消失。

          【讨论】:

            【解决方案9】:

            尝试使用Azure CLI

            例如,如果您想删除以pictures/users 开头的路径,您可以在此处找到所有 blob

            export CONN_STRING="<YOUR-CONNECTION-STRING>"
            
            az storage blob list -c mycontainer \
               --connection-string $CONN_STRING \
               --output tsv \
               --prefix pictures/users
            

            或者,也许您想直接删除所有这些:

            az storage blob delete-batch -s mycontainer \
               --connection-string $CONN_STRING \
               --pattern pictures/users/*
            

            【讨论】:

              【解决方案10】:

              WindowsAzure.Storage 包在 9.4.0 版中被拆分为单独的包。这意味着 accepted answer 中使用的 API 在更新的 Azure.Storage.Blobs 包中发生了变化。

              以下方法使用较新的 Azure.Storage.Blobs 包中的 API,但仍使用相同的方法来接受答案,即列出所有 blob,然后一次删除一个。

              string ConnectionString = "<your connection string>";
              string ContainerName = "<your container name>";
              
              private BlobContainerClient ContainerClient()
              {
                  var client = new BlobContainerClient(ConnectionString, ContainerName);
                  client.CreateIfNotExists();
                  return client;
              }
              
              public async Task<List<BlobItem>> ListBlobsAsync(string folder)
              {
                  var c = ContainerClient();
                  var enumerator = c.GetBlobsByHierarchyAsync(prefix: folder).GetAsyncEnumerator();
              
                  var result = new List<BlobItem>();
                  while (await enumerator.MoveNextAsync())
                  {
                      if (enumerator.Current.IsBlob)
                          result.Add(enumerator.Current.Blob);
                  }
                  return result;
              }
              
              public async Task DeleteByFolderAsync(string folder)
              {
                  var c = ContainerClient();
                  foreach (var blob in await ListBlobsAsync(folder))
                  {
                      await c.GetBlobClient(blob.Name).DeleteIfExistsAsync(DeleteSnapshotsOption.IncludeSnapshots);
                  }
              }
              

              【讨论】:

                【解决方案11】:

                实现所需行为的一些简单代码:

                    public static async Task DeleteFolder(string containerName, string folder)
                    {
                        CloudBlobContainer container = await GetContainerAsync(containerName);
                
                        BlobResultSegment blobList = null;
                        bool folderIsEmpty = false;
                
                        while (!folderIsEmpty)
                        {
                            blobList = await container.ListBlobsSegmentedAsync(
                                prefix: folder,
                                useFlatBlobListing: true,
                                blobListingDetails: BlobListingDetails.None,
                                maxResults: null,
                                currentToken: null,
                                options: null,
                                operationContext: null
                            );
                
                            folderIsEmpty = true;
                
                            foreach (IListBlobItem item in blobList.Results)
                            {
                                folderIsEmpty = false;
                                await ((CloudBlockBlob)item).DeleteIfExistsAsync();
                            }
                        }
                    }
                

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 2019-04-13
                  • 2019-07-15
                  • 2021-10-09
                  • 2018-08-29
                  • 2018-04-13
                  • 2016-07-29
                  • 2020-04-09
                  • 2017-05-20
                  相关资源
                  最近更新 更多