Azure Python SDK中list_blobs与get_paths用法是否等价?
问题描述
我正在使用Python SDK从经典Azure Blob存储中获取Blob列表,实现代码如下:
from azure.storage.blob import BlobServiceClient ... def __init__ (self, key, blob_accnt_name): self._blob_acct_url = f'https://{blob_accnt_name}.blob.core.windows.net' self.blob_service_client = BlobServiceClient(account_url=self._blob_acct_url, credential=key) self.container_client = self.blob_service_client.get_container_client(azure_blob_storage.get_container()) def fetchBlob(self): blob_items = container_client.list_blobs(name_starts_with='{}'.format(blob_path)) ############# (1) blob_paths =[] if any(True for _ in blob_items): blob_paths.append(.... ...
针对ADLS Gen2存储,我尝试使用file_system_client的get_paths方法获取路径列表,实现代码如下:
import os, uuid, sys from azure.storage.filedatalake import DataLakeServiceClient from azure.core._match_conditions import MatchConditions from azure.storage.filedatalake._models import ContentSettings # 初始化ADLS账户的函数 def initStorage(storage_account_name, storage_account_key): try: global service_client service_client = DataLakeServiceClient(account_url="{}://{}.dfs.core.windows.net".format( "https", storage_account_name), credential=storage_account_key) except Exception as e: print(e) # 列出目录内容的函数 def listDirectoryContents(): try: file_system_client = service_client.get_file_system_client(file_system="<container-name>") # ADLS Gen2中的文件系统名对应容器名 paths = file_system_client.get_paths(path="<directory-name>") ################ (2) for path in paths: print(path.name + '\n') except Exception as e: print(e)
现咨询:上述代码标记(1)处的container_client.list_blobs方法,与标记(2)处的file_system_client.get_paths方法,二者的使用方式、返回逻辑是否一致?
回答
两个方法的使用方式、返回逻辑均不一致,核心差异如下:
定位与参数匹配逻辑差异
container_client.list_blobs是为经典Blob存储的扁平命名空间设计的,经典Blob存储本身没有真实的目录实体,所谓目录只是Blob名称里的/分割出来的虚拟路径。该方法的name_starts_with参数是纯字符串前缀匹配:只要Blob的完整名称以传入的字符串开头,就会被命中返回,没有目录边界的概念,默认返回所有匹配到的Blob,不存在递归/非递归的控制参数。file_system_client.get_paths是为ADLS Gen2的分层命名空间设计的,ADLS Gen2有真实的目录实体。该方法的path参数是指定要枚举的目标目录路径,不是前缀匹配:它只会返回该目录层级下的内容,默认递归返回所有子级文件、子目录,可通过传入recursive=False参数只返回当前目录下的直接子项。
举个直观的对比案例:假设容器/文件系统下存在三个路径:
a/b.txt、a/b/c.txt、ab/d.txt
- 调用
list_blobs(name_starts_with='a')时,三个路径全部会被返回,因为三个路径的字符串都以a开头- 调用
get_paths(path='a')时,只会返回a/b.txt、a/b/、a/b/c.txt,ab/d.txt因为不属于a目录下的内容,不会被返回
返回内容结构差异
list_blobs返回的迭代项全是Blob对象,不会单独返回虚拟目录条目,每个项的属性都是Blob专属属性,比如blob_type、content_length、etag、访问层级等。get_paths返回的迭代项同时包含文件和目录两类实体,每个项自带is_directory布尔字段标识类型,除基础属性外还会返回ADLS Gen2专属的POSIX权限、所有者、ACL等属性;如果对未开启分层命名空间的存储账号调用该方法,会直接抛出异常。
使用注意事项
- 如果要让
list_blobs实现和get_paths(path=某目录, recursive=True)近似的枚举效果,不能直接把目录名传给name_starts_with,需要传入目录名 + '/'作为前缀,否则会把同前缀但不属于该目录的Blob也查出来,比如前面案例里的ab/d.txt。 - 两个方法在不传路径类参数时,行为表面相似:
list_blobs()会返回容器下所有Blob,get_paths()会从根目录递归枚举所有内容,但后者会额外返回目录条目,和前者只返回文件的逻辑依然有区别。
内容的提问来源于stack exchange,提问作者Tim
相关产品推荐
相关产品推荐

