使用Python从Azure Data Lake Gen2指定路径的所有子目录批量下载文件
使用Python从Azure Data Lake Gen2指定路径的所有子目录批量下载文件
嘿,我懂你现在的痛点——你已经能搞定单个文件夹的文件下载,但面对嵌套的子目录就没办法递归处理了对吧?而且原代码还可能遇到子目录里文件名重复导致覆盖的问题,我来帮你调整代码解决这些问题。
首先,先说说你原代码的几个小问题:
- 调用
get_paths时没加recursive=True参数,默认只会返回当前目录下的文件和子目录,不会深入遍历 - 直接取路径的最后一段作为文件名,要是子目录里有同名文件,下载到本地会被覆盖
- 没有在本地创建和ADLS里对应的子目录结构,所有文件都会堆在同一个文件夹里
下面是修改后的完整代码,实现了递归遍历所有子目录,并且在本地保留对应的目录结构:
from azure.storage.filedatalake import FileSystemClient, DataLakeServiceClient from azure.identity import ClientSecretCredential from pathlib import Path import os import logging # 初始化日志 logging.basicConfig(level=logging.ERROR) log = logging.getLogger(__name__) def download_to_local( credential: ClientSecretCredential, storage_account_name: str, file_system_name: str, root_directory: str, destination_root: str, ): # 确保本地根目录存在 Path(destination_root).mkdir(parents=True, exist_ok=True) # 创建DataLake服务客户端 service_client = DataLakeServiceClient( account_url=f"https://{storage_account_name}.dfs.core.windows.net/", credential=credential, ) file_system_client = service_client.get_file_system_client(file_system=file_system_name) # 递归获取所有文件路径(recursive=True会遍历所有子目录) all_paths = file_system_client.get_paths(path=root_directory, recursive=True) try: for path in all_paths: # 跳过目录,只处理文件 if path.is_directory: continue # 计算文件相对于根目录的相对路径 relative_path = os.path.relpath(path.name, root_directory) # 构建本地保存路径 local_file_path = os.path.join(destination_root, relative_path) # 确保本地子目录存在 Path(os.path.dirname(local_file_path)).mkdir(parents=True, exist_ok=True) # 获取文件客户端并下载 file_client = file_system_client.get_file_client(path.name) download_stream = file_client.download_file() downloaded_bytes = download_stream.readall() with open(local_file_path, 'wb') as local_file: local_file.write(downloaded_bytes) print(f"已下载文件: {path.name} -> {local_file_path}") except Exception as e: log.error(f"下载过程中出现错误: {str(e)}") # 调用示例(替换成你的实际参数) if __name__ == "__main__": # 你的Azure AD凭据 credential = ClientSecretCredential( tenant_id="你的租户ID", client_id="你的客户端ID", client_secret="你的客户端密钥" ) # ADLS Gen2参数 storage_account_name = "xyz" file_system_name = "abc" root_directory = "rock/final_update/ROCK_OrdersDetails" destination_root = "/tmp/rock/final_update/ROCK_OrdersDetails" download_to_local(credential, storage_account_name, file_system_name, root_directory, destination_root)
关键修改点说明:
- 递归遍历:在
get_paths里添加recursive=True,这样就能获取到指定根目录下所有层级的文件路径 - 保留目录结构:通过
os.path.relpath计算文件相对于根目录的路径,然后在本地创建对应的子目录,避免文件覆盖 - 跳过目录:判断
path.is_directory,只处理文件,跳过目录项 - 修正服务客户端URL:原代码的account_url写错了,正确格式应该是
https://{storage_account_name}.dfs.core.windows.net/,之前的把file_system_name放进去是错误的
注意事项:
- 确保你的服务主体(ClientSecretCredential对应的身份)有ADLS Gen2目标路径的读取权限(比如Storage Blob Data Reader角色)
- 本地路径要确保有足够的读写权限
- 你使用的
azure-storage-file-datalake 12.10.0版本完全支持recursive参数,不用担心版本兼容问题
备注:内容来源于stack exchange,提问作者Kashyap
相关产品推荐
相关产品推荐

