【问题标题】:Getting blob count in an Azure Storage container获取 Azure 存储容器中的 blob 计数
【发布时间】:2011-10-15 06:25:19
【问题描述】:

获取 Azure 存储容器中 blob 数量的最有效方法是什么?

现在我想不出除了下面的代码之外的任何方法:

CloudBlobContainer container = GetContainer("mycontainer");
var count = container.ListBlobs().Count();

【问题讨论】:

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


    【解决方案1】:

    如果您只想知道容器中有多少 Blob 而无需编写代码,您可以使用 Microsoft Azure Storage Explorer application。

    1. 打开所需的 BlobContainer
    2. 单击文件夹统计图标
    3. 观察“活动”窗口中的 blob 计数

    【讨论】:

    • 统计信息仅适用于普通存储帐户。如果 ADLS Gen2 被激活,它们将不可用。
    • 与 blob API 相比,@kap OTOH 列表文件使用 ADLSgen2 API 的速度非常快。
    【解决方案2】:

    我尝试使用 ListBlobs() 对 Blob 进行计数,对于一个包含大约 400,000 个项目的容器,我花了 5 多分钟。

    如果您可以完全控制容器(即,您可以控制写入发生的时间),您可以在容器元数据中缓存大小信息,并在每次移除或插入项目时更新它。这是一段将返回容器 blob 计数的代码:

    static int CountBlobs(string storageAccount, string containerId)
    {
        CloudStorageAccount cloudStorageAccount = CloudStorageAccount.Parse(storageAccount);
        CloudBlobClient blobClient = cloudStorageAccount.CreateCloudBlobClient();
        CloudBlobContainer cloudBlobContainer = blobClient.GetContainerReference(containerId);
    
        cloudBlobContainer.FetchAttributes();
    
        string count = cloudBlobContainer.Metadata["ItemCount"];
        string countUpdateTime = cloudBlobContainer.Metadata["CountUpdateTime"];
    
        bool recountNeeded = false;
    
        if (String.IsNullOrEmpty(count) || String.IsNullOrEmpty(countUpdateTime))
        {
            recountNeeded = true;
        }
        else
        {
            DateTime dateTime = new DateTime(long.Parse(countUpdateTime));
    
            // Are we close to the last modified time?
            if (Math.Abs(dateTime.Subtract(cloudBlobContainer.Properties.LastModifiedUtc).TotalSeconds) > 5) {
                recountNeeded = true;
            }
        }
    
        int blobCount;
        if (recountNeeded)
        {
            blobCount = 0;
            BlobRequestOptions options = new BlobRequestOptions();
            options.BlobListingDetails = BlobListingDetails.Metadata;
    
            foreach (IListBlobItem item in cloudBlobContainer.ListBlobs(options))
            {
                blobCount++;
            }
    
            cloudBlobContainer.Metadata.Set("ItemCount", blobCount.ToString());
            cloudBlobContainer.Metadata.Set("CountUpdateTime", DateTime.Now.Ticks.ToString());
            cloudBlobContainer.SetMetadata();
        }
        else
        {
            blobCount = int.Parse(count);
        }
    
        return blobCount;
    }
    

    当然,这假设您在每次修改容器时更新 ItemCount/CountUpdateTime。 CountUpdateTime 是一种启发式保护措施(如果容器确实在没有人更新 CountUpdateTime 的情况下被修改,这将强制重新计数)但它并不可靠。

    【讨论】:

    • 如果这种方法用于可以并行执行调用的系统中,例如一个 Web API,然后您会遇到关于谁最后更新值的竞争条件。另一种方法可能是将文件名作为索引存储在 Azure 存储表中。
    • 好吧,也许不是存储表,因为它没有原生计数方法,只有“获取所有项目”。也许是 DocumentDB 表或相对昂贵的 SQL 表。
    • 或者,由于 blob 和表实体具有用于检测并发问题的 ETag,因此您可以拥有 1 个带有文件名计数或列表的 blob/实体。
    【解决方案3】:

    API 不包含容器计数方法或属性,因此您需要执行与您发布的内容类似的操作。但是,如果返回的项目超过 5,000 个(或者如果您指定要返回的最大 # 并且列表超过该数量),则需要处理 NextMarker。然后,您将根据 NextMarker 进行 add'l 调用并添加计数。

    编辑:根据 smarx:SDK 应该为您处理 NextMarker。如果您在 API 级别工作,则需要处理 NextMarker,通过 REST 调用 List Blobs。

    或者,如果您正在控制 blob 插入/删除(例如,通过 wcf 服务),您可以使用 blob 容器的元数据区域来存储您在每次插入或删除时计算的缓存容器计数。您只需要处理对容器的写入并发。

    【讨论】:

    • 我很确定 ListBlobs 会自动跟随延续标记。 (所以我认为你不需要对 NextMarker 做任何明确的事情来让它工作。)
    • 糟糕!我在 API 级别上花费了太多时间,看来... :)
    【解决方案4】:

    使用 PHP API 和 getNextMarker 的示例。

    计算 Azure 容器中的 Blob 总数。 这需要很长时间:100000 个 blob 大约需要 30 秒。

    (假设我们有一个有效的 $connectionString 和一个 $container_name)

    $blobRestProxy = ServicesBuilder::getInstance()->createBlobService($connectionString);
    $opts = new ListBlobsOptions();
    $nblobs = 0;
    
    while($cont) {
    
      $blob_list = $blobRestProxy->listBlobs($container_name, $opts);      
    
      $nblobs += count($blob_list->getBlobs());
    
      $nextMarker = $blob_list->getNextMarker();
    
      if (!$nextMarker || strlen($nextMarker) == 0) $cont = false;
      else $opts->setMarker($nextMarker);
    }
    echo $nblobs;
    

    【讨论】:

      【解决方案5】:

      如果您不使用虚拟目录,以下将按照之前的回答进行。

      CloudBlobContainer container = GetContainer("mycontainer");
      var count = container.ListBlobs().Count();
      

      但是,如果您使用的是虚拟目录,上述代码 sn-p 可能没有所需的计数。

      例如,如果您的 blob 存储类似于以下内容:/container/directory/filename.txt 其中 blob 名称 = 目录/文件名.txt container.ListBlobs().Count();只会计算你有多少“/directory”虚拟目录。如果要列出虚拟目录中包含的 blob,则需要在 ListBlobs() 调用中设置 useFlatBlobListing = true。

      CloudBlobContainer container = GetContainer("mycontainer");
      var count = container.ListBlobs(null, true).Count();
      

      注意:使用 useFlatBlobListing = true 的 ListBlobs() 调用是更昂贵/更慢的调用...

      【讨论】:

      • 我有完全不同的经历:做平面列表比列出根目录要快得多,然后用根前缀分别列出每个子文件夹。
      【解决方案6】:

      使用 Azure Storage 的 Python API 就像:

      from azure.storage import *
      blob_service = BlobService(account_name='myaccount', account_key='mykey')
      blobs = blob_service.list_blobs('mycontainer')
      len(blobs)  #returns the number of blob in a container
      

      【讨论】:

      • 这是不正确的。 list_blobs 的上限为 5,000
      • 对于第一个请求,它通常会返回所有 blob,但 @Shane 对于后续请求是正确的,您仍然有 5,000 个限制。
      • 所以.... 答案是什么? python API 是只返回前 5000,还是返回所有内容?有没有办法从 Python API 返回所有内容,还是有问题?
      【解决方案7】:

      另一个 Python 示例,运行缓慢但处理 >5000 个文件时正确:

      from azure.storage.blob import BlobServiceClient
      
      constr="Connection string"
      container="Container name"
      
      blob_service_client = BlobServiceClient.from_connection_string(constr)
      container_client = blob_service_client.get_container_client(container)
      blobs_list = container_client.list_blobs()
      
      num = 0
      size = 0
      for blob in blobs_list:
          num += 1
          size += blob.size
          print(blob.name,blob.size)
      
      print("Count: ", num)
      print("Size: ", size)
      

      【讨论】:

        【解决方案8】:

        我花了相当长的时间来找到以下解决方案 - 我不希望像我这样的人浪费时间 - 所以即使在 9 年后也能在这里回复

        package com.sai.koushik.gandikota.test.app;
        
        import com.microsoft.azure.storage.CloudStorageAccount;
        import com.microsoft.azure.storage.blob.*;
        
        
        public class AzureBlobStorageUtils {
        
        
            public static void main(String[] args) throws Exception {
                AzureBlobStorageUtils getCount =  new AzureBlobStorageUtils();
                String storageConn = "<StorageAccountConnection>";
                String blobContainerName = "<containerName>";
                String subContainer =  "<subContainerName>";
                Integer fileContainerCount = getCount.getFileCountInSpecificBlobContainersSubContainer(storageConn,blobContainerName, subContainer);
                System.out.println(fileContainerCount);
            }
        
            public Integer getFileCountInSpecificBlobContainersSubContainer(String storageConn, String blobContainerName, String subContainer) throws Exception {
                try {
                    CloudStorageAccount storageAccount = CloudStorageAccount.parse(storageConn);
                    CloudBlobClient blobClient = storageAccount.createCloudBlobClient();
                    CloudBlobContainer blobContainer = blobClient.getContainerReference(blobContainerName);
                    return ((CloudBlobDirectory) blobContainer.listBlobsSegmented().getResults().stream().filter(listBlobItem -> listBlobItem.getUri().toString().contains(subContainer)).findFirst().get()).listBlobsSegmented().getResults().size();
                } catch (Exception e) {
                    throw new Exception(e.getMessage());
                } 
            }
        
        }
        
        
        

        【讨论】:

        • listBlobsSegmented,获取前 5000 个,至少在早期的 SDK 中。
        【解决方案9】:

        考虑到其他答案中的所有性能问题,这里是利用 IAsyncEnnumerable 的 Azure SDK v12 版本。这需要对 System.Linq.Async 的包引用。

        public async Task<int> GetBlobCount()
        {
            var container = await GetBlobContainerClient();
            var blobsPaged = container.GetBlobsAsync();
            return await blobsPaged
                .AsAsyncEnumerable()
                .CountAsync();
        }
        

        【讨论】:

          【解决方案10】:

          计算经典和新 Blob 存储帐户中的所有 Blob。该解决方案基于 @gandikota-saikoushik,适用于具有大量 blob 的 blob 容器。

          //setup set values from Azure Portal
          var accountName = "<ACCOUNTNAME>";
          var accountKey = "<ACCOUTNKEY>";
          var containerName = "<CONTAINTERNAME>";
          uristr = $"DefaultEndpointsProtocol=https;AccountName={accountName};AccountKey={accountKey}";
          
          var storageAccount = Microsoft.WindowsAzure.Storage.CloudStorageAccount.Parse(uristr);
          var client = storageAccount.CreateCloudBlobClient();
          var container = client.GetContainerReference(containerName);
          BlobContinuationToken continuationToken = new BlobContinuationToken();
          blobcount = CountBlobs(container, continuationToken).ConfigureAwait(false).GetAwaiter().GetResult();
          Console.WriteLine($"blobcount:{blobcount}");
          
          
          public static async Task<int> CountBlobs(CloudBlobContainer container, BlobContinuationToken currentToken)
          {
              BlobContinuationToken continuationToken = null;
              var result = 0;
              do
              {
                  var response = await container.ListBlobsSegmentedAsync(continuationToken);
                  continuationToken = response.ContinuationToken;
                  result += response.Results.Count();
              }
              while (continuationToken != null);
          
              return result;
          }
          

          【讨论】:

            猜你喜欢
            • 2020-09-05
            • 1970-01-01
            • 2021-12-06
            • 2020-09-03
            • 2018-05-07
            • 2016-09-21
            • 1970-01-01
            • 1970-01-01
            • 2022-11-11
            相关资源
            最近更新 更多