查看: 44|回复: 0

python实现阿里云OSS文件上传下载

[复制链接]
发表于 2020-3-22 22:41:56 | 显示全部楼层 |阅读模式
一 前言
最近使用到阿里云的产品OSS,用于临时存储线上抽取的数据,然后起本地化的流程去OSS拉回本地,进行自动化数据验证。OSS提供了web方式的管理控制台,命令行管理工具,提供了主流的SDK支持,而且自身保证OSS数据的一致性,上传下载自带数据校验。然而,如果将它纳入到自动化流程中,就需要脚本化支持对它进行操作或管理,本文使用python实现一个简单的OSS上传下载的操作类。
二 OSS简介
阿里云对象存储服务(Object Storage Service,简称 OSS),是阿里云提供的海量、安全、低成本、高可靠的云存储服务。其数据设计持久性不低于99.9999999999%(12 个 9),服务设计可用性(或业务连续性)不低于 99.995%。
OSS 具有与平台无关的 RESTful API 接口,您可以在任何应用、任何时间、任何地点存储和访问任意类型的数据。
您可以使用阿里云提供的 API、SDK 接口或者 OSS 迁移工具轻松地将海量数据移入或移出阿里云 OSS。数据存储到阿里云 OSS 以后,您可以选择标准存储(Standard)作为移动应用、大型网站、图片分享或热点音视频的主要存储方式,也可以选择成本更低、存储期限更长的低频访问存储(Infrequent Access)和归档存储(Archive)作为不经常访问数据的存储方式。
三 OSS操作的四个基本概念
访问密钥(AccessKey)= AccessKeyId + AccessKeySecret
AccessKey(简称 AK)指的是访问身份验证中用到的 AccessKeyId 和 AccessKeySecret。OSS 通过使用 AccessKeyId 和 AccessKeySecret 对称加密的方法来验证某个请求的发送者身份。AccessKeyId 用于标识用户;AccessKeySecret 是用户用于加密签名字符串和 OSS 用来验证签名字符串的密钥,必须保密。
访问域名(Endpoint)
Endpoint 表示 OSS 对外服务的访问域名。OSS 以 HTTP RESTful API 的形式对外提供服务,当访问不同地域的时候,需要不同的域名。通过内网和外网访问同一个地域所需要的域名也是不同的。
存储空间(Bucket)
存储空间是您用于存储对象(Object)的容器,所有的对象都必须隶属于某个存储空间。存储空间具有各种配置属性,包括地域、访问权限、存储类型等。您可以根据实际需求,创建不同类型的存储空间来存储不同的数据。
四 python实现的OSS上传下载类
访问一个OSS,需要拿到AccessKeyId ,AccessKeySecret,Endpoint,Bucket,通过这四个信息即可建立OSS的连接,根据访问密钥具备的权限可以对bucket的对象进行操作,如,新建、删除、上传、下载等。
下面是python实现的OSS上传下载类,支持对指定OSS对象的目录层级或文件进行批量下载,或批量上传,仅供参考。

  1. import oss2
  2. import os
  3. import datetime


  4. class OSS(object):
  5.     """定义一个简单的oss操作类,支持文件上传和下载"""

  6.     def __init__(self, accessKey_id, accessKey_secret, endpoint, bucket_name):
  7.         self.auth = oss2.Auth(accessKey_id, accessKey_secret)
  8.         self.bucket = oss2.Bucket(self.auth, endpoint, bucket_name)

  9.     def download_from_oss(self, oss_folder_prefix, object_name, local_save_path):
  10.         """拼接本地保存时的文件路径,且保持oss中指定目录以下的路径层级"""
  11.         oss_path_prefix = object_name.split(oss_folder_prefix)[-1]  # oss原始路径,以'/'为路径分隔符
  12.         oss_path_prefix = os.sep.join(oss_path_prefix.strip('/').split('/'))  # 适配win平台
  13.         local_file_path = os.path.join(local_save_path, oss_path_prefix)
  14.         local_file_prefix = local_file_path[:local_file_path.rindex(os.sep)]  # 本地保存文件的前置路径,如果不存在需创建
  15.         if not os.path.exists(local_file_prefix):
  16.             os.makedirs(local_file_prefix)
  17.         self.bucket.get_object_to_file(object_name, local_file_path)

  18.     def upload_to_oss(self, prefix, suffix, local_upload_path):
  19.         """上传指定路径下的目录或文件,如果oss路径不存在,则自动创建"""
  20.         # 当前日期时间作为最新上传的目录名
  21.         folder_name = datetime.datetime.now().strftime('%Y%m%d%H%M%S')
  22.         oss_upload_prefix = prefix.rstrip('/') + '/' + folder_name
  23.         # 遍历指定上传目录文件,并上传
  24.         for root, dirs, files in os.walk(local_upload_path):
  25.             local_upload_path = local_upload_path.rstrip(os.sep)  # 去除外部输入时结尾可能带入的路径符号
  26.             for file in files:
  27.                 file_path = os.path.join(root, file)
  28.                 relative_file_path = file_path.split(local_upload_path)[1]  # 保持upload目录下的路径层级
  29.                 relative_file_path = relative_file_path.strip(os.sep)
  30.                 oss_relative_path = relative_file_path.replace(os.sep, '/')  # 转换成oss的路径格式,适配linux\win
  31.                 oss_upload_path = oss_upload_prefix + '/' + oss_relative_path
  32.                 # 上传该文件
  33.                 if file.endswith(suffix):
  34.                     self.bucket.put_object_from_file(oss_upload_path, file_path)

  35.     def travel_download(self, prefix, suffix, local_save_path):
  36.         """
  37.         :param prefix: oss目录前缀,即遍历以prefix开头的文件
  38.         :param suffix: 文件后缀名,如,.csv,指定下载何种类型的文件
  39.         :param local_save_path: 下载文件的保存路径
  40.         :return:
  41.         """
  42.         # 下载指定目录下的指定后缀的文件,且保存时维持目录层级格式
  43.         # 列举指定prefix目录下的层级目录,定位到目标目录后,再做深度遍历
  44.         local_save_path = local_save_path.rstrip(os.sep)  # 去除外部输入时结尾可能带入的路径符号
  45.         top_level_folder = []
  46.         for obj in oss2.ObjectIterator(self.bucket, prefix=prefix, delimiter='/'):
  47.             if obj.is_prefix():
  48.                 # 目录
  49.                 top_level_folder.append(obj.key)
  50.             else:
  51.                 # 文件
  52.                 pass

  53.         # 获取最近一次更新的目录,并下载该目录及其子目录下指定后缀的文件
  54.         target_folder = max(top_level_folder)

  55.         for obj in oss2.ObjectIterator(self.bucket, prefix=target_folder):
  56.             if obj.is_prefix():
  57.                 # 目录
  58.                 continue
  59.             else:
  60.                 # 只下载指定后缀的文件,oss中xxx/xxx/也会被认为是文件,根据prefix而定
  61.                 if obj.key.endswith(suffix):
  62.                     # 下载
  63.                     self.download_from_oss(target_folder, obj.key, local_save_path)
复制代码

五 一些使用体会
1) OSS是基于key-value的分布式存储模式,不同于层级式的存储,所以,遍历一个存储对象时,形如xxx/xxxx/的对象,也可能是文件类型,而不是目录,取决于你的prefix,可以使用obj.is_prefix()判断,当返回True时,表明是公共前缀(目录);
2) 上传时,如果oss不存在对应的路径,会自动创建,无需开发者关心,类似于执行了os.makedirs(multi_level_path)创建指定的目录后,再上传文件;
3) 同名文件直接覆盖,不存在时,自动创建,类似于文件操作的w+模式;


原文链接:

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关闭

站长推荐上一条 /1 下一条

快速回复 返回顶部 返回列表