Skip to content
大纲

概述

本文档主要介绍FOS Python SDK的安装和使用。在使用本文档前,您需要先了解FOS的一些基本知识,并已开通了FOS服务。若您还不了解FOS,可以参考"产品描述"和"快速入门"。

安装SDK工具包

环境准备

  1. 运行环境

Python SDK支持在Python2.7和Python3.x 的环境下运行。

  1. 安装pycrypto依赖 安装SDK之前,需要先执行命令pip install pycrypto安装pycrypto依赖。 如果安装失败,请执行pip install pycryptodome
  2. 查看当前使用的SDK版本
python
import flymefce
print(flymefce.SDK_VERSION)

下载和安装

您可以通过pip安装的方式将Python SDK安装到您的环境中。 联网状态下,在命令行中执行如下命令:

bash
pip install flymefce

即可将Python SDK安装到本地。 SDK目录结构

flemyfce
├── auth                                //公共权限目录
├── http                                //Http请求模块
├── services                            //服务公共目录
│     └── fos                           //FOS目录
│           ├──fos_client.py            //FOS客户端入口类
│           ├──fos_handle.py            //HTTP reponse处理函数
│           ├──canned_acl.py            //权限控制需要的常量
│           └──storage_class.py         //存储类型定义模块
├── fce_base_client.py                  //FCE客户端入口类的基类
├── fce_client_configuration.py         //针对FOS特有的HttpClient的配置类
├── fce_response.py                     //FCE客户端的请求类
├── exception.py                        //FCE客户端的异常类
├── protocol.py                         //网络协议定义
├── region.py                           //区域处理模块
├── retry_policy.py                     //FCE服务公共配置类
└── utils.py                            //FCE公用工具类

卸载SDK

预期卸载 SDK 时,使用pip卸载 flymefce 即可。

初始化

快速入门

  1. 初始化一个FosClient。 FosClient是与FOS服务交互的客户端,FOS Python SDK的FOS操作都是通过FosClient完成的。用户可以参考"FosClient"。完成初始化客户端的操作。
  2. 新建一个Bucket。 Bucket是FOS上的命名空间,相当于数据的容器,可以存储若干数据实体(Object)。用户可以参考"新建Bucket"来完成新建一个Bucket的操作。
  3. 上传Object。 Object是FOS中最基本的数据单元,用户可以把Object简单的理解为文件。用户可以参考"上传Object"完成对Object的上传。
  4. 列出指定Bucket中的全部Object。 当用户完成一系列上传后,可以参考"查看Bucket中Object列表"来查看指定Bucket下的全部Object。
  5. 获取指定Object 用户可以参考"获取Object"来实现对一个或者多个Object的获取。

确认Endpoint

目前暂时支持一个Endpoint,对应信息为:

https://fos.flymeyun.com

获取密钥

要使用Flyme云FOS,您需要拥有一个有效的AK(Access Key ID)和SK(Secret Access Key)用来进行签名认证。AK/SK是由系统分配给用户的,均为字符串,用于标识用户,为访问FOS做签名验证。 目前情况下,请联系售后人员获取可使用的密钥列表。

新建FosClient

FosClient是FOS服务的客户端,为开发者与FOS服务进行交互提供了一系列的方法。

使用AK/SK新建FosClient

FosClient是FOS服务的Python客户端,为调用者与FOS服务进行交互提供了一系列的方法。

  1. 在新建FosClient之前,需要先创建配置文件对FosClient进行配置,以下将此配置文件命名为fos_sample_conf.py,具体配置信息如下所示:
python
#!/usr/bin/env python
#coding=utf-8

#从Python SDK导入FOS配置管理模块以及安全认证模块
from flymefce.fce_client_configuration import FceClientConfiguration
from flymefce.auth.fce_credentials import FceCredentials

#设置FosClient的Host,Access Key ID和Secret Access Key
fos_host = "https://fos.flymeyun.com"
access_key_id = "AK"
secret_access_key = "SK"

#创建FceClientConfiguration
config = FceClientConfiguration(credentials=FceCredentials(access_key_id, secret_access_key), endpoint = fos_host)

在上面代码中,ACCESS_KEY_ID对应控制台中的“Access Key ID”,SECRET_ACCESS_KEY对应控制台中的“Access Key Secret”,获取方式请参考控制台"快速上手"。

  1. 在完成上述配置之后,参考如下代码新建一个FosClient。
python
#导入FosClient配置文件
import fos_sample_conf

#导入FOS相关模块
from flymefce import exception
from flymefce.services import fos
from flymefce.services.fos import canned_acl
from flymefce.services.fos.fos_client import FosClient

#新建FosClient
fos_client = FosClient(fos_sample_conf.config)

配置FosClient

设置网络参数

用户可以设置一些网络参数:

python
#设置请求超时时间
fos_sample_conf.config.connection_timeout_in_mills = TIMEOUT

#设置接收缓冲区大小
fos_sample_conf.config.recv_buf_size(BUF_SIZE)
#设置发送缓冲区大小
fos_sample_conf.config.send_buf_size(BUF_SIZE)
#设置连接重试策略#三次指数退避重试
fos_sample_conf.config.retry_policy = BackOffRetryPolicy()
#不重试
fos_sample_conf.config.retry_policy = NoRetryPolicy()

参数说明

通过fos_client_configuration能指定的所有参数如下表所示:

参数说明
portFOS端口号
send_buf_size发送缓冲区大小
recv_buf_size接收缓冲区大小
connection_timeout_in_mills请求超时时间(单位:毫秒)
retry_policy连接重试策略,初始化Client时默认为三次指数退避

Bucket管理

概述

Bucket既是FOS上的命名空间,也是计费、权限控制、日志记录等高级功能的管理实体。

  • Bucket名称具有全局唯一性,且不能修改。
  • 存储在FOS上的每个Object都必须包含在一个Bucket中。
  • 一个用户最多可创建100个Bucket,但每个Bucket中存放的Object的数量和大小总和没有限制,用户不需要考虑数据的可扩展性。

Bucket权限管理

设置Bucket的访问权限

如下代码将Bucket的权限设置为了private:

python
fos_client.set_bucket_canned_acl(bucket_name, canned_acl.PRIVATE)

其中canned_acl中包含三个参数:PRIVATE、PUBLIC_READ、PUBLIC_READ_WRITE,它们分别对应的相关权限为:private、public-read、public-read-write。

设置更多Bucket访问权限

  1. 通过设置referer白名单方式设置防盗链
python
myAcl =[{"grantee":[{"id": "*"}],
    "permission":["FULL_CONTROL"],
    "condition":{"referer":{"stringEquals":["http://test/index"]}}}]

fos_client.set_bucket_acl(bucket_name, myAcl)
  1. 限制客户端IP访问,只允许部分客户端IP访问
python
myAcl = [{"grantee":[{"id":"*"}],
    "permission":["FULL_CONTROL"],
    "condition":{"ipAddress":["192.170.0.6"]}}]

fos_client.set_bucket_acl(bucket_name, myAcl)

查看Bucket的权限

如下代码可以查看Bucket的权限:

python
response = fos_client.get_bucket_acl(bucket_name)

fos_client.set_bucket_acl(bucket_name, response.access_control_list)

get_bucket_acl方法返回的解析类中可供调用的参数有:

参数说明
ownerBucket owner信息
+idBucket owner的用户ID
access_control_list标识Bucket的权限列表
+grantee标识被授权人
++id被授权人ID
+permission标识被授权人的权限
+resourceACL配置项所影响的资源

新建Bucket

如下代码可以新建一个Bucket

python
if not fos_client.does_bucket_exist(bucket_name):
    fos_client.create_bucket(bucket_name)

注意: 由于Bucket的名称在所有区域中是唯一的,所以需要保证bucketName不与其他所有区域上的Bucket名称相同。 Bucket的命名有以下规范:

  • 只能包括小写字母,数字,短横线(-)。
  • 必须以小写字母或者数字开头。
  • 长度必须在4-63字节之间。

列举Bucket

用如下方式可以列出用户所有的Bucket:

python
response = fos_client.list_buckets()
for bucket in response.buckets:
    print(bucket.name)

list_buckets方法返回的解析类中可供调用的参数如下:

参数说明
ownerBucket Owner信息
+idBucket Owner的用户ID
+display_nameBucket Owner的名称
buckets存放多个Bucket信息的容器
bucket存放一个Bucket信息的容器
+nameBucket名称
+creation_dateBucket创建时间
+locationBucket所属的区域

删除Bucket

如下代码可以删除一个Bucket:

python
fos_client.delete_bucket(bucket_name)

注意:

  • 如果Bucket不为空(即Bucket中有Object和未完成的三步上传Part存在),则Bucket无法被删除,必须清空Bucket后才能成功删除。
  • 在删除前确认该Bucket没有开通跨区域复制,不是跨区域复制规则中的源Bucket或目标Bucket,否则不能删除。

判断Bucket是否存在

若用户需要判断某个Bucket是否存在,则如下代码可以做到:

python
# 获取Bucket的存在信息,需要传入bucket名称,返回值为布尔型
exists = fos_client.does_bucket_exist(bucket_name)
# 输出结果
if exists:
    print("Bucket exists")
else:
    print("Bucket not exists")

Bucket生命周期管理

应用场景

一个数据是有其生命周期的,从创建到归档到删除可以认为是一个完整的循环。创建之初的数据往往需要频繁访问读取,之后迅速冷却归档,最终被删除。生命周期管理就是对象存储服务帮助用户自动化管理数据的生命周期。 通常可以服务于以下场景:

  1. 数据达到一定寿命后自动归档或删除。
  2. 指定时间执行操作。

新建Lifecycle配置

如下代码新建了一个Lifecycle配置

python
rule = {}
rule['id'] = 'rule1'
rule['status'] = 'enabled'
rule['action'] = {}
rule['action']['name'] = 'Transition'
rule['action']['storageClass'] = 'STANDARD_IA'
#对flymefosmty2里所有Object生效
rule['resource'] = ['flymefosmty2/*']
rule['condition'] = {}
rule['condition']['time'] = {'dateGreaterThan': 'XXXX-XX-XXTXX:XX:XXZ'}
rules=[]
rules.append(rule)
fos_client.put_bucket_lifecycle(bucket_name, rules)

注意:

  1. 只有Bucket的Owner拥有full control才能够进行此操作。
  2. "resource"指明规则对哪些资源生效。例如,对samplebucket里以prefix/为前缀的Object生效:samplebucket/prefix/;对samplebucket里所有Object生效:samplebucket/

读取Bucket的Lifecycle配置

如下代码可读取Bucket的Lifecycle配置

python
response = fos_client.get_bucket_lifecycle(bucket_name)

删除Bucket Lifecycle

如下代码可以删除Bucket的lifecycle:

python
fos_client.delete_bucket_lifecycle(bucket_name)

Bucket跨域资源访问

应用场景

跨域资源共享(CORS)允许WEB端的应用程序访问不属于本域的资源。FOS提供接口方便开发者控制跨域访问的各种权限。

设定CORS规则

如下代码设定了一个CORS规则:

python
conf = {}
conf['allowedOrigins'] = ['http://www.boluor.com']
conf['allowedMethods'] = ['GET', 'HEAD', 'DELETE']
conf['allowedHeaders'] = ['Authorization', 'x-fce-test', 'x-fce-test2']
conf['allowedExposeHeaders'] = ['user-custom-expose-header']
conf['maxAgeSeconds'] = 3600
confs = []
#每个Bucket最多允许有100条规则。
confs.append(conf)
fos_client.put_bucket_cors(bucket_name, confs)

注意:

  1. 如果原规则存在则覆盖原规则。
  2. 只有Bucket的所有者和被授予FULL_CONTROL权限的用户才能设置Bucket的CORS。没有权限时,返回403 Forbidden错误,错误码:AccessDenied。

获取Bucket的CORS规则

如下代码可获取Bucket的CORS配置:

python
response = fos_client.get_bucket_cors(bucket_name)

关闭Bucket的CORS功能并清空所有规则

如下代码可以关闭Bucket的CORS功能并清空所有规则:

python
fos_client.delete_bucket_cors(bucket_name)

事件通知

put_notification

本接口用于指定bucket上增加通知规则。

注意:

  • 只有bucket owner或者full control权限才能获取这个bucket的配置。
  • 如果不是bucket owner则返回403,如果对应的文件不存在则返回404。
python
notifications = list()
notifications.append(
    {
        "resources": ["/"],
        "encryption": {"key": "06a62b70f47dc4a0a7da349609f1a1ac"},
        "status": "enabled",
        "name": "name3",
        "id": "r3",
        "appId": "p3",
        "events": [
            "AppendObject",
            "CompleteMultipartUpload",
            "CopyObject",
            "PutObject",
            "PostObject",
            "FetchObject",
            "DeleteObject"
        ],
        "apps": [
            {
                "eventUrl": "http://www.liujiang.com",
                "id": "ImageCensor",
                "xVars": "{\"saveUrl\": \"http://xxx.com/ocr\"}"
            }
        ]
    }
)
response = fos_client.put_notification(bucket_name, notifications)

get_notification

本接口用于获取指定bucket上的通知规则。

python
response = fos_client.get_notification(bucket_name)

delete_notification

本接口用于删除指定bucket上的通知规则。

注意: 该接口为一次性全部删除当前bucket下全部规则

python
response = fos_client.delete_notification(bucket_name)

文件管理

上传文件

在FOS中,用户操作的基本数据单元是Object。Bucket中的Object数量不限,但单个Object最大允许存储5TB的数据。Object包含Key、Meta和Data。其中,Key是Object的名字;Meta是用户对该Object的描述,由一系列Name-Value对组成;Data是Object的数据。 FOS Python SDK提供了丰富的文件上传接口,可以通过以下方式上传文件:

  • 简单上传
  • 追加上传
  • 分片上传
  • 断点续传上传
  • 获取上传进度

Object的命名规范如下:

  • 使用UTF-8编码。
  • 长度必须在1-1023字节之间。
  • 首字母不能为'/',不能包含'@'字符,'@'用于图片处理接口。

简单上传

FOS在简单上传的场景中,支持以指定文件形式、以数据流方式、以字符串方式执行Object上传,请参考如下代码:

  1. 如下代码可以进行Object上传:
python
data = open(file_name, 'rb')
#以数据流形式上传Object,用户需要自行计算数据长度content_length
#用户需自行计算content_md5.计算方法是对数据执行md5算法获取128位二进制数据,再进行base64编码
fos_client.put_object(bucket_name, object_key, data, content_length,content_md5)
#从字符串中上传的Object
fos_client.put_object_from_string(bucket_name, object_key, string)
#从文件中上传的Object
fos_client.put_object_from_file(bucket_name, object_key, file_name)

其中,data为流对象,不同类型的Object采用不同的处理方法,从字符串中的上传使用StringIO的返回,从文件中的上传使用open()的返回,因此FOS提供了封装好的接口方便用户进行快速上传。 Object以文件的形式上传到FOS中,put_object相关接口均支持不超过5GB的Object上传。在put_object、put_object_from_string或者put_object_from_file请求处理成功后,FOS会在Header中返回Object的ETag作为文件标识。 这些接口均有可选参数:

参数说明
content_type上传文件或字符串的类型
content_md5文件数据校验,设置后FOS会启用文件内容MD5校验,把您提供的MD5与文件的MD5比较,不一致会抛出错误
content_length定义文件长度,put_object_from_string()不包含该参数
content_sha256用于进行文件校验
user_metadata用户自定义元数据
user_headers用户定义header

content_md5计算方法是对数据执行md5算法获取128位二进制数据,再进行base64编码。示例如下:

python
import io
import hashlib
import base64

file_name = "your_file"
buf_size = 8192
with open(file_name, 'rb') as fp:
    md5 = hashlib.md5()
    while True:
        bytes_to_read = buf_size
        buf = fp.read(bytes_to_read)
        if not buf:
            break
        md5.update(buf)
    content_md5 = base64.standard_b64encode(md5.digest())

设置文件元信息

文件元信息(Object Meta),是对用户在向FOS上传文件时,同时对文件进行的属性描述,主要分为分为两种:设置HTTP标准属性(HTTP Headers)和用户自定义的元信息。 设定Object的Http Header FOS Python SDK本质上是调用后台的HTTP接口,因此用户可以在上传文件时自定义Object的Http Header。常用的http header说明如下:

名称描述默认值
Cache-Control指定该Object被下载时的网页的缓存行为
Content-Encoding表示消息主体进行了何种方式的内容编码转换
Content-Disposition指示MINME用户代理如何显示附加的文件,打开或下载,及文件名称
Expires缓存过期时间

参考代码如下:

  • 从字符串中上传带有特定header的object
python
user_headers = {"header_key":"header_value"}
#从字符串中上传带有特定header的object
fos_client.put_object_from_string(bucket=bucket_name,
                                  key=object_key,
                                  data=string,
                                  user_headers=user_headers)
#从文件中上传带有特定header的object
fos_client.put_object_from_file(bucket=bucket_name,
                                key=object_key,
                                file_name=file,
                                user_headers=user_headers)

用户自定义元信息

FOS支持用户自定义元数据来对Object进行描述。如下代码所示:

python
#用户自定义元数据
 user_metadata = {"name":"my-data"}
 #从字符串中上传带有用户自定义meta的object
 fos_client.put_object_from_string(bucket=bucket_name,
                                   key=object_key,
                                   data=string,
                                   user_metadata=user_metadata)
 #从文件中上传带有用户自定义meta的object
 fos_client.put_object_from_file(bucket=bucket_name,
                                 key=object_key,
                                 file_name=file,
                                 user_metadata=user_metadata)

提示:

  • 在上面代码中,用户自定义了一个名字为”name”,值为”my-data”的元数据
  • 当用户下载此Object的时候,此元数据也可以一并得到
  • 一个Object可以有多个类似的参数,但所有的User Meta总大小不能超过2KB

设置Object的Copy属性

FOS同时会提供copy_object接口用于将一个已经存在的Object拷贝到另外一个Object,拷贝过程中会对源Object的Etag或修改状态进行判断,根据判断结果决定是否执行拷贝。详细的参数解释如下:

名称类型描述是否必需
x-ic-copy-source-if-matchString如果源Object的ETag值和用户提供的ETag相等,则执行拷贝操作,否则拷贝失败。
x-ic-copy-source-if-none-matchString如果源Object的ETag和用户提供的ETag不相等,则执行拷贝操作,否则拷贝失败。
x-ic-copy-source-if-unmodified-sinceString如果源object在x-ic-copy-source-if-unmodified-since之后没被修改,则执行拷贝操作,否则拷贝失败。
x-ic-copy-source-if-modified-sinceString如果源object在x-ic-copy-source-if-modified-since之后被修改了,则执行拷贝操作,否则拷贝失败。

对应的示例代码:

python
copy_object_user_headers = {"copy_header_key":"copy_header_value"}

fos_client.copy_object(source_bucket_name = bucket_name,
                       source_key = object_name,
                       target_bucket_name = bucket_name,
                       target_key = object_name,
                       user_metadata = user_metadata,
                       user_headers = user_headers,
                       copy_object_user_headers = copy_object_user_headers)

追加上传

上文介绍的简单上传方式,创建的Object都是Normal类型,用户不可再进行追加写,这在日志、视频监控、视频直播等数据复写较频繁的场景中使用不方便。 正因如此,Flyme云FOS支持AppendObject,即以追加写的方式上传文件。通过AppendObject操作创建的Object类型为Appendable Object,可以对该Object追加数据。AppendObject大小限制为0~5G。归档存储类型不支持追加上传。 通过AppendObject方式上传示例代码如下:

python
#上传appendable object。其中“content_md5(data)”表示需要用户自行计算上传数据的md5值。
 #content_md5计算方法是对数据执行md5算法获取128位二进制数据,再进行base64编码。示例见上文“简单上传”部分。#其中“content_length(data)”表示需要用户自行计算上传数据的长度
 response = fos_client.append_object(bucket_name=bucket_name,
                                     key=object_key,
                                     data=data,
                                     content_md5=content_md5(data),
                                     content_length=content_length(data))
 #获取下次追加写的位置
 next_offset = response.metadata.ic_next_append_offset
 fos_client.append_object(bucket_name=bucket_name,
                          key=object_key,
                          data=next_data,
                          content_md5=content_md5(next_data),
                          content_length=content_length(next_data),
                          offset=next_offset)
 #从字符串上传appendable object
 from flymefce.services.fos import storage_class
 fos_client.append_object_from_string(bucket_name=bucket_name,
                                      key=object_key,
                                      data=string,
                                      offset=offset,
                                      storage_class=storage_class.STANDARD,
                                      user_headers=user_headers)

分块上传

除了通过putObject接口上传文件到FOS以外,FOS还提供了另外一种上传模式 —— Multipart Upload。用户可以在如下的应用场景内(但不仅限于此),使用Multipart Upload上传模式,如:

  • 需要支持断点上传。
  • 上传超过5GB大小的文件。
  • 网络条件较差,和FOS的服务器之间的连接经常断开。
  • 需要流式地上传文件。
  • 上传文件之前,无法确定上传文件的大小。

下面将介绍分步实现Multipart Upload。

初始化Multipart Upload

FOS使用initiate_multipart_upload方法来初始化一个分块上传事件:

python
upload_id = fos_client.initiate_multipart_upload(bucket_name, object_key).upload_id

该方法会返回InitMultipartUploadResponse对象,此对象中包含uploadId参数,用来表示此次的上传事件。

带有特定header的分块上传的初始化

python
fos_client.initiate_multipart_upload(bucket_name=bucket,
                                     key=object_key,
                                     user_headers=user_headers)

其中,header可设置的属性有:"Cache-Control"、"Content-Encoding"、"Content-Disposition"、"Expires",get-object和get-object-meta两个接口会返回设置的这四个header。

上传分块

初始化完成后,进行分块上传:

python
left_size = os.path.getsize(file_name)
 # left_size用于设置分块开始位置
 # 设置分块的开始偏移位置
 offset = 0

 part_number = 1
 part_list = []
 while left_size > 0:
     # 设置每块为5MB
     part_size = 5 * 1024 * 1024
     if left_size < part_size:
         part_size = left_size

     response = fos_client.upload_part_from_file(
         bucket_name, object_key, upload_id, part_number, part_size, file_name, offset)

     left_size -= part_size
     offset += part_size
     part_list.append({
         "partNumber": part_number,
         "eTag": response.metadata.etag
     })

     part_number += 1

注意:

  1. offset参数以字节为单位,为分块的开始偏移位置。
  2. size参数以字节为单位,定义每个分块的大小,除最后一个Part以外,其他的Part大小都要大于5MB。但是Upload Part接口并不会立即校验上传Part的大小;只有当调用complete_multipart_upload()的时候才会校验。
  3. 为了保证数据在网络传输过程中不出现错误,建议您在Upload Part后,使用每个分块FOS返回的Content-MD5值分别验证已上传分块数据的正确性。当所有分块数据合成一个Object后,不再含MD5值。
  4. Part号码的范围是1~10000。如果超出这个范围,FOS将返回InvalidArguement的错误码。
  5. 每次上传Part时都要把流定位到此次上传块开头所对应的位置。
  6. 每次上传Part之后,FOS的返回结果会包含一个etag与块编号(partNumber),在后续完成分块上传的步骤中会用到它,因此需要将其保存起来。一般来讲这些 etag和partNumber将被保存到List中。

完成分块上传

python
fos_client.complete_multipart_upload(bucket_name, object_key, upload_id, part_list)

其中,part_list类型是list,里面每个元素是个dict,每个dict包含两个关键字,一个是partNumber, 一个是eTag。 示例如下:

python
[
    {'partNumber': 1, 'eTag': 'f1c9645dbc14efddc7d8a322685f26eb'},
    {'partNumber': 2, 'eTag': 'f1c9645dbc14efddc7d8a322685f26eb'},
    {'partNumber': 3, 'eTag': '93b885adfe0da089cdf634904fd59f71'}
]

该方法返回的解析类中可供调用的参数有:

参数说明
bucketBucket名称
keyObject名称
e_tag每个上传分块的ETag
locationObject的URL

注意:此对象中包含的ETag是上传分块过程中每个Part的ETag,FOS收到用户提交的Part列表后,会逐一验证每个数据Part的有效性。当所有的数据Part验证通过后,FOS将把这些数据part组合成一个完整的Object。

取消分块上传事件

用户可以使用abort_multipart_upload方法取消分块上传:

python
fos_client.abort_multipart_upload(bucket_name, object_key, upload_id = upload_id)

获取未完成的分块上传事件

用户可以使用如下两种方法获取Bucket中未完成的分块上传事件: 方法一:

python
response = fos_client.list_multipart_uploads(bucket_name)
for item in response.uploads:
    print(item.upload_id)

list_multipart_uploads每次FOS最多返回1000个Multipart Upload,FOS支持prefix和delimiter过滤。 list_multipart_uploads方法可供调用的参数还有:

名称类型描述是否必需
delimiterString分隔符; 主要应此项实现list文件夹的逻辑
key_markerStringObject按照字典序排序后,本次从keyMarker的后面的一条开始返回
max_uploadsInt本次请求返回Multipart Uploads的最大数目,默认1000,最大1000
prefixStringkey前缀,限定返回的object key必须以此为前缀

list_multipart_uploads方法返回的解析类中可供调用的参数有:

参数说明
bucketBucket名称
key_marker开始上传的分块Object名称
next_key_marker当指定了delimiter且IsTruncated true时,才返回此项,作为下次查询marker的值
is_truncated指明是否所有查询都返回了;false-本次已经返回所有结果,true-本次还没有返回所有结果
prefix匹配以prefix开始到第一次出现Delimiter字符之间的object作为一组元素返回
common_prefixes仅当指定delimiter,才会返回此项
delimiter查询的结束符
max_uploads请求返回的最大数目
uploads全部未完成的分快上传事件容器
+owner对应Bucket所属用户信息
+idBucket Owner的用户id
+display_nameBucket Owner的名称
+key分块所属Object名称
+upload_id分块上传id
+initiated分块上传开始时间

list_all_multipart_uploads方法返回uploads的生成器(Generator),并且不受单次最大返回1000个结果的限制,会返回所有的结果。 方法二:

python
uploads = fos_client.list_all_multipart_uploads(bucket_name)
for item in uploads:
    print(item.upload_id)

获取所有已上传的块信息

用户可以使用如下两种方法获取某个上传事件中所有已上传的块: 方法一:

python
response = fos_client.list_parts(bucket_name, object_key, upload_id)
for item in response.parts:
    print(item.part_number)

注意:

  1. FOS按照PartNumber升序排序。
  2. 由于网络传输可能出错,所以不推荐用ListParts出来的结果生成最后CompleteMultipartUpload的Part列表。

list_parts方法可供调用的参数还有:

名称类型描述是否必需
max_partsIntFOS一次最多返回的part数目,默认1000,最大1000
part_number_markerInt按照partNumber排序,本次请求的起始part从此partNumber的下一个开始返回

list_parts方法返回的解析类中可供调用的参数有:

参数说明
bucketBucket名称
keyObject名称
initiated本次分块上传开始时间
max_parts请求返回的最大数目
is_truncated指明是否所有查询都返回了;false-本次已经返回所有结果,true-本次还没有返回所有结果
storage_classObject的存储类型,目前分为标准类型STANDARD, 低频类型STANDARD_IA、冷存储类型COLD 和归档类型ARCHIVE
part_number_marker分块开始标记位
parts分块列表,list类型
+part_number分块编号
+last_modified此分块最后一次被修改的时间
+e_tag每个上传分块的ETag
+size分块内容的大小(字节数)
upload_id本次分块上传的id
owner对应bucket所属用户信息
+idBucket owner的用户id
+display_nameBucket owner的名称
next_part_number_marker本次请求返回的最后一条记录的partNumber,可以作为下一次请求的part_number_marker

方法二:

python
parts = fos_client.list_all_parts(bucket_name, object_key, upload_id = upload_id)
for item in parts:
    print(item.part_number)

list_all_parts方法返回parts的生成器(Generator),并且不受单次最大返回1000个结果的限制,会返回所有的结果。

获取分块上传的Object的存储类型

python
response = fos_client.list_parts(bucket_name=bucket,
                                 key=object_key,
                                 upload_id=upload_id)
print(response.storage_class)

封装分块上传

在Python SDK中,FOS为用户提供了put_super_obejct_from_file()接口,它对分块上传涉及到的initiate_multipart_upload、upload_part_from_file、complete_multipart_upload三个方法进行封装,用户只需调用该接口即可完成分块上传。

python
import multiprocessing

file_name = "/path/to/file.zip"
result = fos_client.put_super_obejct_from_file(bucket_name, key, file_name,
                                               chunk_size=5, thread_num=multiprocessing.cpu_count())
if result:
    print("Upload success!")

方法可供调用的参数还有:

名称类型描述是否必需
chunk_sizeint分块大小,单位MB。默认为5MB
thread_numint分块上传中线程池中线程的数量,默认等于CPU的核数

若一个大文件耗时很长,用户想结束分块上传,可调用UploadTaskHandle中的cancel()方法实现取消分块上传操作。示例如下:

python
import threading
from flymefce.services.fos.fos_client import UploadTaskHandle

file_name = "/path/to/file.zip"
uploadTaskHandle = UploadTaskHandle()
t = threading.Thread(target=fos_client.put_super_obejct_from_file,
                     args=(bucket_name, key, file_name),
                     kwargs={"chunk_size": 5,
                             "thread_num": multiprocessing.cpu_count(),
                             "uploadTaskHandle": uploadTaskHandle})
t.start()
time.sleep(2)
uploadTaskHandle.cancel()
t.join()

断点续传上传

当用户向FOS上传大文件时,如果网络不稳定或者遇到程序崩等情况,则整个上传就失败了,失败前已经上传的部分也作废,用户不得不重头再来。这样做不仅浪费资源,在网络不稳定的情况下,往往重试多次还是无法完成上传。 基于上述场景,FOS提供了断点续传上传的能力:

  • 当网络情况一般的情况下,建议使用三步上传方式,将object分为1Mb的块,参考"分块上传"。
  • 当您的网络情况非常差,推荐使用appendObject的方式进行断点续传,每次append 较小数据256kb,参考"追加上传"。

    提示

    • 断点续传是分片上传的封装和加强,是用分片上传实现的;
    • 文件较大或网络环境较差时,推荐使用分片上传;

获取上传进度

Python SDK支持在上传过程中实时提供上传进度信息。目前支持简单上传,追加上传,分块上传。需要在对应接口上增加progress_callback参数,并提供进度条回调函数,也可调用工具类中的默认进度条回调函数。 回调函数示例如下:

python
def percentage(consumed_bytes, total_bytes):
    """
    进度条回调函数,计算当前完成的百分比
    :param consumed_bytes: 已经上传/下载的数据量
    :param total_bytes: 总数据量
    """
    if total_bytes:
        rate = int(100 * (float(consumed_bytes) / float(total_bytes)))
        print('\r{0}% '.format(rate))
        sys.stdout.flush()

# progress_callback为可选参数,用于实现进度条功能.
fos_client.put_object(bucket_name, object_key, data, content_length,content_md5, progress_callback=percentage)

推荐使用工具类中的默认进度条回调函数(utils.default_progress_callback),目前支持百分比和进度条展示,示例如下:

python
# 引入 SDK 工具类包
from flymefce import utils

# progress_callback为可选参数,用于实现进度条功能.
fos_client.put_object(bucket_name, object_key, data, content_length,content_md5, progress_callback=utils.default_progress_callback)
  • put_object 示例代码
python
# 引入 SDK 工具类包
from flymefce import utils

# progress_callback为可选参数,用于实现进度条功能.
data = open(file_name, 'rb')
fos_client.put_object(bucket_name, object_key, data, content_length, content_md5,
                      progress_callback=utils.default_progress_callback)
#从字符串中上传的Object
fos_client.put_object_from_string(bucket_name, object_key, string,
                                  progress_callback=utils.default_progress_callback)
#从文件中上传的Object
fos_client.put_object_from_file(bucket_name, object_key, file_name,
                                progress_callback=utils.default_progress_callback)
  • append_object 示例代码
python
# 引入 SDK 工具类包
from flymefce import utils

# progress_callback为可选参数,用于实现进度条功能.
#上传appendable object。
response = fos_client.append_object(bucket_name=bucket_name,
                                    key=object_key,
                                    data=data,
                                    content_md5=content_md5(data),
                                    content_length=content_length(data),
                                    progress_callback=utils.default_progress_callback)
#从字符串上传appendable object
result = fos_client.append_object_from_string(bucket_name=bucket_name,
                                              key=object_key,
                                              data=String,
                                              progress_callback=utils.default_progress_callback)
  • upload_part_from_file 示例代码
python
# 引入 SDK 工具类包
from flymefce import utils

# progress_callback为可选参数,用于实现进度条功能.
fos_client.upload_part_from_file(bucket_name, key, upload_id, part_number, part_size,
                                 file_name, offset,
                                 progress_callback=utils.default_progress_callback)

支持单链接限速

对象存储FOS对单Bucket的公网带宽阈值为10Gbit/s,内网带宽阈值为50Gbit/s,当用户的上传或下载占用带宽达到带宽限制阈值时,会返回RequestRateLimitExceeded的错误码。为保证用户能够正常使用服务,FOS支持在进行上传、下载等行为时进行流量控制,保证大流量服务占用带宽不会对其他应用服务造成影响。

上传类请求接口示例

限速值的取值范围为819200~838860800,单位为bit/s,即100KB/s~100MB/s。限速值取值必须为数字,FOS将按照指定的限速值对此次请求进行限速,当限速值不在此范围或不合法时将返回400错误码。

python
traffic_limit_speed = 819200 * 5
# put a file as object
_create_file(file_name, 5 * 1024 * 1024)
fos_client.put_object_from_file(bucket_name, key, file_name, traffic_limit=traffic_limit_speed)

# multi-upload operation samples
# put a super file to object
_create_file(file_name, 10 * 1024 * 1024)

# SuperFile step 1: init multi-upload
upload_id = fos_client.initiate_multipart_upload(bucket_name, key).upload_id

# SuperFile step 2: upload file part by part
left_size = os.path.getsize(file_name)
offset = 0
part_number = 1
part_list = []
while left_size > 0:
    part_size = 5 * 1024 * 1024
    if left_size < part_size:
        part_size = left_size

    response = fos_client.upload_part_from_file(bucket_name, key, upload_id, part_number, part_size, file_name, offset, traffic_limit=traffic_limit_speed)
    left_size -= part_size
    offset += part_size
    # your should store every part number and etag to invoke complete multi-upload
    part_list.append({"partNumber": part_number,"eTag": response.metadata.etag})
    part_number += 1

# copy a object
fos_client.copy_object(source_bucket, source_key, target_bucket, target_key, traffic_limit=traffic_limit_speed)

# append object
fos_client.append_object(bucket_name, key, traffic_limit=traffic_limit_speed)

# upload part copy
fos_client.upload_part_copy(source_bucket, source_key, target_bucket, target_key, upload_id, part_number,
 part_size, offset, traffic_limit=traffic_limit_speed)

下载文件

FOS Python SDK提供了丰富的文件下载接口,用户可以通过以下方式从FOS中下载文件:

  • 简单流式下载
  • 下载到本地文件
  • 下载为字符串
  • 断点续传下载
  • 范围下载
  • 获取下载进度

简单的读取Object

用户可以通过如下代码将Object读取到一个流中:

python
response = fos_client.get_object(bucket_name, object_key)
s = response.data

#  处理Object
...

# 关闭流
response.data.close()

直接下载Object到文件或字符串

用户可以参考如下代码将Object下载到指定文件:

python
fos_client.get_object_to_file(bucket_name, object_key, file_name)

用户可以参考如下代码将Object下载到字符串:

python
result = fos_client.get_object_as_string(bucket_name, object_key)
print(result)

范围下载

为了实现更多的功能,可以通过使用指定range参数来指定下载范围,实现更精细化地获取Object。如果指定的下载范围是0 - 100,则返回第0到第100个字节的数据,包括第100个,共101字节的数据,即[0, 1000]。

python
range = [0,1000]
#返回指定范围的Object数据
print(fos_client.get_object_as_string(bucket_name, object_key, range = range))
#返回指定范围的Object数据到文件中
fos_client.get_object_to_file(bucket_name, object_key, file_name, range = range)

通过get_object_as_string和get_object_to_file的range参数可以设置返回Object的范围。用户也可以用此功能实现文件的分段下载和断点续传。

其他使用方法

只获取ObjectMetadata

通过get_object_meta_data方法可以只获取Object的元数据,而非Object实体。如下代码所示:

python
response = fos_client.get_object_meta_data(bucket_name, object_key)

get_object_meta_data方法返回的解析类中可供调用的参数有:

参数说明
content_lengthObject的大小
e_tagObject的HTTP协议实体标签
ic_meta如果在PutObject指定了user_metadata自定义meta,则返回此项()
ic_restore归档存储对象处于正在取回或已经取回时返回。对于正在取回的归档对象ic_restore取值为 ongoing-request="true";对于已取回的归档对象ic_restore取值为 ongoing-request="false", expiry-date="Wed, 07 Nov 2019 00:00:00 GMT"。其中expiry-date表示对象取回后的失效时间,此时间为格林尼治时间。

获取下载进度

Python SDK支持在下载过程中实时提供下载进度信息。目前支持下载object 到文件。需要在对应接口上增加progress_callback参数,并提供进度条回调函数,也可调用工具类中的默认进度条回调函数。 回调函数示例如下:

python
def percentage(consumed_bytes, total_bytes):
    """
    进度条回调函数,计算当前完成的百分比
    :param consumed_bytes: 已经上传/下载的数据量
    :param total_bytes: 总数据量
    """
    if total_bytes:
        rate = int(100 * (float(consumed_bytes) / float(total_bytes)))
        print('\r{0}% '.format(rate))
        sys.stdout.flush()

# progress_callback为可选参数,用于实现进度条功能.
fos_client.get_object_to_file(bucket_name, key, download, progress_callback=percentage)

推荐使用工具类中的默认进度条回调函数(utils.default_progress_callback),目前支持百分比和进度条展示,示例如下:

python
# 引入 SDK 工具类包
from flymefce import utils

# progress_callback为可选参数,用于实现进度条功能.
fos_client.get_object_to_file(bucket_name, key, download, progress_callback=utils.default_progress_callback)
  • get_object_to_file 代码示例
python
# 引入 SDK 工具类包
from flymefce import utils

# progress_callback为可选参数,用于实现进度条功能.
fos_client.get_object_to_file(bucket_name, key, download, progress_callback=utils.default_progress_callback)

支持单链接限速

对象存储FOS对单Bucket的公网带宽阈值为10Gbit/s,内网带宽阈值为50Gbit/s,当用户的上传或下载占用带宽达到带宽限制阈值时,会返回RequestRateLimitExceeded的错误码。为保证用户能够正常使用服务,FOS支持在进行上传、下载等行为时进行流量控制,保证大流量服务占用带宽不会对其他应用服务造成影响。

下载类请求接口示例

限速值的取值范围为819200~838860800,单位为bit/s,即100KB/s~100MB/s。限速值取值必须为数字,FOS将按照指定的限速值对此次请求进行限速,当限速值不在此范围或不合法时将返回400错误码。

python
traffic_limit_speed = 819200 * 5

# get obj url by traffic limit
param = {}
param[b'x-ic-traffic-limit'] = traffic_limit_speed
url = fos_client.generate_pre_signed_url(bucket_name, key, timestamp=1649923427,
                                         expiration_in_seconds=1000,
                                         params=param)
__logger.debug("[Sample] get object url is  %s", url)

# get object into file
fos_client.get_object_to_file(bucket_name, key, download, traffic_limit=traffic_limit_speed)
__logger.debug("[Sample] get object into file, file size:%s", os.path.getsize(download))

获取文件下载URL

用户可以通过如下示例代码获取指定Object的URL:

python
url = fos_client.generate_pre_signed_url(bucket_name, object_key, timestamp, expiration_in_seconds)

说明:

  • timestamp为可选参数,不配置时,默认值为当前时间。
  • timestamp为时间戳,标识URL有效起始时间,timestamp=int(time.time()),并需要* import time。
  • expriation_in_seconds用来设置URL的有效时长,为可选参数,不配置时,默认值为1800秒。如果要设置为永久不失效的时间,可以将expirationInSeconds参数设置为 -1,不可设置为其他负数。

列举存储空间中的文件

FOS SDK支持用户通过以下两种方式列举出object:

  • 简单列举
  • 通过参数复杂列举

除此之外,用户还可在列出文件的同时模拟文件夹

简单列举

当用户完成一系列上传后,可能会需要查看在指定Bucket中的全部Object,可以通过如下代码实现:

python
response = fos_client.list_objects(bucket_name)
for object in response.contents:
    print(object.key)

注意:

  1. 默认情况下,如果Bucket中的Object数量大于1000,则只会返回1000个Object,并且返回结果中is_truncated值为True,并返回next_marker做为下次读取的起点。
  2. 若想增大返回Object的数目,可以使用Marker参数分次读取。

也可以一次列举当前Bucket的所有的Object。

python
for object in fos_client.list_all_objects(bucket_name):
    print(object.key)

通过参数复杂列举

list_objects方法其他可选的参数有:

参数说明
prefix限定返回的object key必须以Prefix作为前缀。
delimiter是一个用于对Object名字进行分组的字符。所有名字包含指定的前缀且第一次出现Delimiter字符之间的object作为一组元素: CommonPrefixes。
max_keys限定此次返回object的最大数,此数值不能超过1000,如果不设定,默认为1000。
marker设定结果从Marker之后按字母排序的第一个开始返回。

注意:

  1. 如果有Object以Prefix命名,当仅使用Prefix查询时,返回的所有Key中仍会包含以Prefix命名的Object,详见"递归列出目录下所有文件"。
  2. 如果有Object以Prefix命名,当使用Prefix和Delimiter组合查询时,返回的所有Key中会有Null,Key的名字不包含Prefix前缀,详见"查看目录下的文件和子目录"。

下面我们分别以几个案例说明通过参数列举的方法:

指定最大返回条数

python
max_keys = 500
# 指定最大返回条数为500
response = fos_client.list_objects(bucket_name, max_keys = max_keys)
for obj in response.contents:
    print(obj.key)

返回指定前缀的object

python
prefix = "test"
# 指定返回前缀为test的object
response = fos_client.list_objects(bucket_name, prefix = prefix)
for obj in response.contents:
    print(obj.key)

从指定Object后返回

python
marker = "object"
# 用户可以定义不包括某object,从其之后开始返回
response = fos_client.list_objects(bucket_name, marker = marker)
for obj in response.contents:
    print(obj.key)

分页获取所有Object

python
isTruncated = True
# 用户可设置每页最多500条记录
max_keys = 500
marker = None
while isTruncated:
    response = fos_client.list_objects(bucket_name, max_keys = max_keys, marker=marker)
    for obj in response.contents:
        print(obj.key)
    isTruncated = response.is_truncated
    marker = getattr(response,'next_marker',None)

分页获取所有特定Object后的结果

python
# 用户可设置每页最多500条记录,并从某特定object之后开始获取
max_keys = 500
marker = "object"
isTruncated = True
while isTruncated:
    response = fos_client.list_objects(bucket_name, max_keys = max_keys, marker=marker)
    for obj in response.contents:
        print(obj.key)
    isTruncated = response.is_truncated
    marker = getattr(response,'next_marker',None)

分页获取所有指定前缀的Object结果

python
# 用户可设置分页获取指定前缀的Object,每页最多500条记录
max_keys = 500
prefix = "object"
isTruncated = True
while isTruncated:
    response = fos_client.list_objects(bucket_name, prefix = prefix)
    for obj in response.contents:
        print(obj.key)
    isTruncated = response.is_truncated
    marker = getattr(response,'next_marker',None)

list_objects方法返回的解析类中可供调用的参数有:

参数说明
nameBucket名称
prefix匹配以prefix开始到第一次出现Delimiter字符之间的object作为一组元素返回
marker本次查询的起点
max_keys请求返回的最大数目
is_truncated指明是否所有查询都返回了;false-本次已经返回所有结果,true-本次还没有返回所有结果
contents返回的一个Object的容器
+keyObject名称
+last_modified此Object最后一次被修改的时间
+e_tagObject的HTTP协议实体标签
+sizeObject的内容的大小(字节数)
+ownerObject对应Bucket所属用户信息
++idBucket Owner的用户ID
++display_nameBucket Owner的名称
next_marker只要IsTruncated为true,就会返回next_marker,作为下次查询marker的值
common_prefixes仅当指定delimiter,才会返回此项

list_all_objects方法返回contents的生成器(Generator),并且不受单次最大返回1000个结果的限制,会返回所有的结果。

模拟文件夹功能

在FOS的存储结果中是没有文件夹这个概念的,所有元素都是以Object来存储,但FOS的用户在使用数据时往往需要以文件夹来管理文件。 因此,FOS提供了创建模拟文件夹的能力,其本质上来说是创建了一个size为0的Object。对于这个Object可以上传下载,只是控制台会对以”/“结尾的Object以文件夹的方式展示。 用户可以通过 Delimiter 和 Prefix 参数的配合模拟出文件夹功能。Delimiter 和 Prefix 的组合效果是这样的: 如果把 Prefix 设为某个文件夹名,就可以罗列以此 Prefix 开头的文件,即该文件夹下递归的所有的文件和子文件夹(目录)。文件名在Contents中显示。 如果再把 Delimiter 设置为 “/” 时,返回值就只罗列该文件夹下的文件和子文件夹(目录),该文件夹下的子文件名(目录)返回在 CommonPrefixes 部分,子文件夹下递归的文件和文件夹不被显示。 假设Bucket中有5个文件:fos.jpg,fun/,fun/test.jpg,fun/movie/001.avi,fun/movie/007.avi,把 “/” 符号作为文件夹的分隔符。 如下是几个应用方式:

列出Bucket内所有文件

当用户需要获取Bucket下的所有文件时,可以参考"分页获取所有Object"

递归列出目录下所有文件

可以通过设置 Prefix 参数来获取某个目录下所有的文件:

python
prefix = "fun/"
print("Objects:")
# 递归列出fun目录下的所有文件
response = fos_client.list_objects(bucket_name, prefix = prefix)
for obj in response.contents:
    print(obj.key)

输出:

python
Objects:
fun/
fun/movie/001.avi
fun/movie/007.avi
fun/test.jpg

查看目录下的文件和子目录

在 Prefix 和 Delimiter 结合的情况下,可以列出目录下的文件和子目录:

python
# "/" 为文件夹的分隔符
delimiter = "/"
prefix = "fun/"
# 列出fun目录下的所有文件和文件夹
response = fos_client.list_objects(bucket_name, prefix = prefix, delimiter = delimiter)
print("Objects:")
for obj in response.contents:
    print(obj.key)

# 遍历所有CommonPrefix
print("CommonPrefixs:")
for obj in response.common_prefixes:
    print(obj.prefix)

输出:

python
Objects:
fun/
fun/test.jpg

CommonPrefixs:
fun/movie/

返回的结果中, Objects 的列表中给出的是fun目录下的文件。而 CommonPrefixs 的列表中给出的是fun目录下的所有子文件夹。可以看出 fun/movie/001.avi , fun/movie/007.avi 两个文件并没有被列出来,因为它们属于 fun 文件夹下的 movie 目录。

列举Bucket中object的存储属性

用户除了可以查看指定Bucket中的全部Object,还可以查看Object的存储类型,实现代码如下:

python
response = fos_client.list_objects(bucket_name)
for obj in response.contents:
    print('object:{}, storage_class:{}'.format(obj.key, obj.storage_class))

Object权限控制

设置Object的访问权限

目前FOS支持两种方式设置ACL。第一种是使用Canned Acl,在PutObjectAcl的时候,通过头域的"x-ic-acl"或者"x-ic-grant-permission'来设置object访问权限,当前可设置的权限包括private和public-read,两种类型的header不可以同时在一个请求中出现。第二种方式是上传一个ACL文件。

  1. 通过使用头域的"x-ic-acl"来设置object访问权限
python
from flymefce.services.fos import canned_acl
# 设置object为private权限
fos_client.set_object_canned_acl(bucket_name, object_key, canned_acl=canned_acl.PRIVATE)
# 设置object为public-read权限
fos_client.set_object_canned_acl(bucket_name, object_key, canned_acl=canned_acl.PUBLIC_READ)

查看Object的权限

归档存储类型对象在取回未完成,或者刚上传归档类型文件(时长参考取回时长)时,不能设置Object acl 查看Object的权限如下代码所示:

python
response = fos_client.get_object_acl(bucket_name, object_key)
print("object acl:", response)

getObjectAcl方法返回的解析类中可供调用的参数有:

参数说明
accessControlList标识Object的权限列表
grantee标识被授权人
-id被授权人id
permission标识被授权人的权限

删除Object的权限

归档存储类型对象在取回未完成,或者刚上传归档类型文件(时长参考取回时长)时,不能删除Object acl 如下代码可以删除Object的权限:

python
fos_client.delete_object_acl(bucket_name,object_key)

删除文件

删除一个Object

如下代码删除了一个Object:

python
fos_client.delete_object(bucket_name, object_key)

批量删除Object

用户可以通过如下代码批量删除object

python
key_list = [object_key1, object_key2, object_key3]
fos_client.delete_multiple_objects(bucket_name, key_list)

说明:支持一次请求内最多删除1000个Objcet。

查看文件是否存在

用户可通过如下操作查看某文件是否存在:

python
from flymefce import exception

try:
    response = fos_client.get_object_meta_data(bucket_name, object_key)
    print("Get meta:{}",response.metadata)
except exception.FceError as e:
    print(e)

获取及更新文件元信息

文件元信息(Object Metadata),是对用户上传FOS的文件的属性描述,分为两种:HTTP标准属性(HTTP Headers)和User Meta(用户自定义元信息)。

获取文件元信息

参考"只获取ObjectMetadata"。

修改文件元信息

FOS修改Object的Metadata通过拷贝Object实现。即拷贝Object的时候,把目的Bucket设置为源Bucket,目的Object设置为源Object,并设置新的Metadata,通过拷贝自身实现修改Metadata的目的。如果不设置新的Metadata,则报错。 归档类型文件不支持修改元信息。

python
user_metadata = {'meta_key': 'meta_value'}
fos_client.copy_object(source_bucket_name = bucket_name,
                       source_key = object_name,
                       target_bucket_name = bucket_name,
                       target_key = object_name,
                       user_metadata = user_metadata)
response = fos_client.get_object_meta_data(bucket_name = bucket_name,
                                           key = object_name)
print(response)

拷贝Object

用户可以通过copyObject方法拷贝一个Object,如下代码所示:

python
fos_client.copy_object(source_bucket_name, source_object_key, target_bucket_name, target_object_key)

同步Copy功能

当前FOS的CopyObject接口是通过同步方式实现的。同步方式下,FOS端会等待Copy实际完成才返回成功。同步Copy能帮助用户更准确的判断Copy状态,但用户感知的复制时间会变长,且复制时间和文件大小成正比。 同步Copy方式更符合业界常规,提升了与其它平台的兼容性。同步Copy方式还简化了FOS服务端的业务逻辑,提高了服务效率。 归档类型文件如果是源Object,需要先取回归档类型文件。

分块拷贝

除了通过CopyObject接⼝拷贝文件以外,FOS还提供了另外一种拷贝模式——Multipart Upload Copy。归档类型文件如果是源Object,需要先取回归档类型文件。 用户可以在如下的应用场景内(但不仅限于此),使用Multipart Upload Copy,如:

  • 需要支持断点拷贝。
  • 拷贝超过5GB大小的文件。
  • 网络条件较差,和FOS的服务器之间的连接经常断开。

下面将介绍分步实现三步拷贝。 三步拷贝包含init、“拷贝分块”和complete三步,其中init和complete的操作同分块上传一致,可直接参考"初始化Multipart Upload"和"完成分块上传"。 拷贝分块代码参考(参数定义可参考分块上传):

python
left_size = int(fos_client.get_object_meta_data(source_bucket,source_key).metadata.content_length)

#设置分块开始位置为left_size
#设置分块的开始偏移位置
offset = 0
part_number = 1
part_list = []
while left_size > 0:
    #设置每块为5MB
    part_size = 5 * 1024 * 1024
    if left_size < part_size:
        part_size = left_size

    response = fos_client.upload_part_copy(source_bucket, source_key, target_bucket, target_key, upload_id,part_number, part_size, offset)
    left_size -= part_size
    offset += part_size
    part_list.append({"partNumber": part_number,"eTag": response.etag})
    part_number += 1

注意:

  1. offset参数以字节为单位,为分块的开始偏移位置。
  2. size参数以字节为单位,定义每个分块的大小,除最后一个Part以外,其他的Part大小都要大于 5MB。

异常处理

系统异常

FOS系统异常提示有如下三种方式:

异常方法说明
FceHttpClientError重试时抛出的异常
last_error最后一次重试时抛出的异常
FceClientErrorFOS客户端产生的异常
FceInvalidArgumentError传递参数产生的异常
FceServerErrorFOS服务器产生的异常

用户可以使用try获取某个事件所产生的异常:

python
from flymefce import exception
from flymefce.services import fos

try:
    fos_client.delete_object(bucket_name, object_key)
except exception.FceHttpClientError as e:
    print e.last_error

返回为:

python
FceHttpClientError: Unable to execute HTTP request. Retried 0 times. All trace backs:
Traceback (most recent call last):
File "/home/work/python-2.7/lib/python2.7/site-packages/flymefce/http/fce_http_client.py", line 184, in send_request
if handler_function(http_response, response):
File "/home/work/python-2.7/lib/python2.7/site-packages/flymefce/http/handler.py", line 71, in parse_error raise bse
FceServerError: The specified key does not exist.

客户端异常

客户端异常表示客户端尝试向FOS发送请求以及数据传输时遇到的异常。 例如,当发送请求时网络连接不可用时,则会抛出FceHttpClientError;当上传文件时发生IO异常时,也会抛出FceClientError。

服务端异常

当FOS服务端出现异常时,FOS服务端会返回给用户相应的错误信息,以便定位问题。

参数异常

FOS Python SDK的每个调用都有一些类型固定不可以为空的参数,若该参数传入为空值则返回ValueError,若该参数传入类型错误则返回TypeError。 参数与调用的对应关系如下:

FOS调用参数说明类型
create_bucket, does_bucket_exist, delete_bucket, get_bucket_location, get_bucket_lifecycle, delete_bucket_lifecycle, get_bucket_cors, delete_bucket_cors, get_bucket_logging, delete_bucket_logging, list_objects, list_all_objects, delete_object, get_bucket_acl, list_multipart_uploads, list_all_multipart_uploadsbucket_nameBucket名称string, unicode
put_bucket_loggingsource_bucket,target_bucket源Bucket和目标Bucket名称string, unicode
set_bucket_aclbucket_nameBucket名称string, unicode
aclACL主体包含被授权人及权限list, dict
set_bucket_canned_aclbucket_nameBucket名称string, unicode
canned_aclCannedAcl权限string
put_bucket_lifecyclebucket_nameBucket名称string, unicode
rules生命周期管理规则主体,包含资源及操作动作list, dict
put_bucket_corsbucket_nameBucket名称string, unicode
cors_configuration跨域资源共享(CORS)的规则主体,包含允许的跨域请求的来源及允许的header等list, dict
get_object, get_object_as_string, get_object_meta_data, initiate_multipart_upload, generate_pre_signed_urlbucket_nameBucket名称string, unicode
keyObject名称string
get_object_to_file, put_object_from_filebucket_nameBucket名称string, unicode
keyObject名称string
file_name文件名string
put_object, append_objectbucket_nameBucket名称string, unicode
keyObject名称string
data流对象object
content_length上传Object的大小int, long
content_md5上传Object的MD5string
put_object_from_string,append_object_from_stringbucket_nameBucket名称string, unicode
keyObject名称string
data上传字符串string, unicode
copy_objectsource_bucket_name, target_bucket_name源Bucket和目标Bucket名称string, unicode
source_key, target_key源Object和目标Object名称string
upload_partbucket_name, upload_idBucket名称,标识MultUpload操作全局IDstring, unicode
keyObject名称string
part_number分块编号int
part_size上传分块的大小int, long
part_fp上传分块对象object
upload_part_from_filebucket_name, upload_idBucket名称,标识MultUpload操作全局IDstring, unicode
keyObject名称string
part_number分块编号int
part_size上传分块的大小int, long
file_name文件名string
offset分块的开始偏移位置int
complete_multipart_uploadbucket_name, upload_idBucket名称,标识MultUpload操作全局IDstring, unicode
keyObject名称string
part_list分块列表list
abort_multipart_upload, list_parts, list_all_partsbucket_name, upload_idBucket名称,标识MultUpload操作全局IDstring, unicode
keyObject名称string
delete_multiple_objectsbucket_nameBucket名称string, unicode
key_listobject列表list