如何删除 Azure Blob 容器中的文件夹

How to delete a folder within an Azure blob container

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

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

注意:如有需要请向我索取更多信息

因为 "folders" 实际上并不存在。在 Azure 存储帐户中,您有装满 blob 的容器。您看到的客户可视化为 "folders" 的是帐户 "pictures/uploads/" 中 blob 的文件名。如果要删除 "folder",实际上必须删除每个以相同 "path" 命名的 blob。

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

Windows Azure Blob Storage 没有文件夹的概念。层次结构非常简单:存储帐户 > 容器 > 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) 列出“picture”容器中以“users”开头的blob,您可以删除它们个别地。要删除其他文件夹,您只需要这样指定 GetDirectoryReference("your folder name").

还有一个来自 Microsoft 的桌面存储资源管理器。它有一个功能,您可以 select 虚拟文件夹,然后删除它有效地删除所有子 blob。

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

让我们从如何使用 ListBlobsSegmentedAsyc 删除 "folder" 的示例开始:

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

一个"folder"可能包含很多文件。 ListBlobSegmentedAsyc 可能 return 只是其中的一部分。此令牌将存储信息以在下次调用中继续。

var result = await container.ListBlobsSegmentedAsync("myfolder", true, BlobListingDetails.None, null, ctoken, null, null);
  • 第一个参数是所需的 blob 名称 ("path") 前缀。
  • 第二个参数 "useFlatBlobListing=true" 告诉客户端 return 所有子文件夹中的所有项目。如果设置为 false,它将在 "virtual folders" 模式下 运行 并且表现得像一个文件系统。
  • 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())

触发删除所有结果和return任务列表。

.Where(task => task != null)

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

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

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

提供生命周期管理文档

您现在可以在 ADF 中使用 delete activity 删除任何文件 /blob。它将删除里面的所有文件

您也可以在 Azure 云中完成 shell;这是命令:

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

在最新的 repo 中,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 被删除而消失。

尝试使用 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/*

WindowsAzure.Storage package was split into separate packages at version 9.4.0. This means that the APIs used in the have changed in the more recent 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);
    }
}

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

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

如果是one-time拖,只需安装storage-explorer - 它支持删除目录。