You need to enable JavaScript to run this app.
文档中心
文档控制台
注册
对象存储

对象存储

复制全文
下载 pdf
上传对象
追加上传(Python SDK)
复制全文
下载 pdf
追加上传(Python SDK)

追加上传创建的对象类型为追加类型 (Appendable Object) ,可在对象末尾追加写入数据。而普通上传和分片上传创建的对象类型为普通类型 (Normal Object),无法追加写入数据。

注意事项

  • 追加上传对象前,您必须具有 tos:PutObject 权限,具体操作请参见权限配置指南
  • 上传对象时,对象名必须满足一定规范,详细信息请参见对象命名规范
  • TOS 是面向海量存储设计的分布式对象存储产品,内部分区存储了对象索引数据,为横向扩展您上传对象和下载对象时的最大吞吐量,和减小热点分区的概率,请您避免使用字典序递增的对象命名方式,详细信息,请参见性能优化
  • 如果桶中已经存在同名对象,则新对象会覆盖已有的对象。桶开启多版本的场景下,则会保留原有对象,生成一个新版本号用于标识新上传的对象。
  • 追加上传对象不支持 Chunk-Encoded 的请求方式,当您追加上传网络流时请迭代获取数据再追加上传。

限制说明

使用追加上传时, 限制条件如下:

  • 追加对象大小不能大于 5GiB。
  • 通过追加上传创建的对象,进行普通上传时,对象被覆盖且对象类型由追加类型变为普通类型。反之通过普通上传的对象不支持追加写操作。
  • 追加上传创建的对象不支持拷贝。
  • 如果您的存储桶处于开启或者暂停多版本功能的状态下,或存储桶的类型为低频存储,则无法追加写入对象。

示例代码

追加上传字符流

以下代码用于将字符流追加上传到目标桶 bucket-test 中的 object-test 对象。

from io import StringIO

import os
import tos

from tos import RateLimiter

# 从环境变量获取 AK 和 SK 信息。
ak = os.getenv('TOS_ACCESS_KEY')
sk = os.getenv('TOS_SECRET_KEY')
# your endpoint 和 your region 填写Bucket 所在区域对应的Endpoint。# 以华北2(北京)为例,your endpoint 填写 tos-cn-beijing.volces.com,your region 填写 cn-beijing。
endpoint = "your endpoint"
region = "your region"
bucket_name = "bucket-test"
# 对象名称,例如 example_dir 下的 example_object.txt 文件,则填写为 example_dir/example_object.txt
object_key = "object-test"
try:
    client = tos.TosClientV2(ak, sk, endpoint, region)
    # 创建类型为可追加文件, 首次偏移 offset 设置为0
    # 通过 acl=tos.ACLType.ACL_Private 参数设置对象的访问权限为私有
    # 通过 storage_class=tos.StorageClassType.Storage_Class_Standard 设置对象的存储类型
    content_1 = 'Hello TOS A'
    content_2 = 'Hello TOS B'
    content_3 = 'Hello TOS C'

    # 追加数据, 偏移量从上次响应中获取<next_append_offset>,或者通过 head_object 返回的 content-length获取
    # 创建类型为可追加文件,首次偏移 offset 设置为0
    # 通过 acl=tos.ACLType.ACL_Private 参数设置对象的访问权限为私有
    # 通过 storage_class=tos.StorageClassType.Storage_Class_Standard 设置对象的存储类型
    # 第一次追加写入offset=0,设置pre_hash_crc64_ecma为0
    # 传入 pre_hash_crc64_ecma 保障了append对象数据完整性
    result_1 = client.append_object(bucket_name, object_key, 0, content=StringIO(content_1), pre_hash_crc64_ecma=0)

    # 第二次追加, 偏移量从上次响应中获取<next_append_offset>,或者通过 head_object 返回的 content-length获取。
    # 设置offset=next_append_offset,设置pre_hash_crc64_ecma为上传响应中的hash_crc64_ecma
    # 传入 pre_hash_crc64_ecma 保障了append对象数据完整性
    result_2 = client.append_object(bucket_name, object_key, result_1.next_append_offset, content=StringIO(content_2),
                                    pre_hash_crc64_ecma=result_1.hash_crc64_ecma)

    # 第三次次追加, 偏移量从上次响应中获取<next_append_offset>,或者通过 head_object 返回的 content-length获取。
    # 设置offset=next_append_offset,设置pre_hash_crc64_ecma为上传响应中的hash_crc64_ecma
    # 传入 pre_hash_crc64_ecma 保障了append对象数据完整性
    result_3 = client.append_object(bucket_name, object_key, result_2.next_append_offset, content=StringIO(content_3),
                                    pre_hash_crc64_ecma=result_2.hash_crc64_ecma)
except tos.exceptions.TosClientError as e:
    # 操作失败,捕获客户端异常,一般情况为非法请求参数或网络异常
    print('fail with client error, message:{}, cause: {}'.format(e.message, e.cause))
except tos.exceptions.TosServerError as e:
    # 操作失败,捕获服务端异常,可从返回信息中获取详细错误信息
    print('fail with server error, code: {}'.format(e.code))
    # request id 可定位具体问题,强烈建议日志中保存
    print('error with request id: {}'.format(e.request_id))
    print('error with message: {}'.format(e.message))
    print('error with http code: {}'.format(e.status_code))
    print('error with ec: {}'.format(e.ec))
    print('error with request url: {}'.format(e.request_url))
except Exception as e:
    print('fail with unknown error: {}'.format(e))

追加上传 Bytes 流

以下代码用于将 Bytes 流追加上传到目标桶 bucket-test 中的 object-test 对象。

from io import BytesIO

import os
import tos


# 从环境变量获取 AK 和 SK 信息。
ak = os.getenv('TOS_ACCESS_KEY')
sk = os.getenv('TOS_SECRET_KEY')
# your endpoint 和 your region 填写Bucket 所在区域对应的Endpoint。# 以华北2(北京)为例,your endpoint 填写 tos-cn-beijing.volces.com,your region 填写 cn-beijing。
endpoint = "your endpoint"
region = "your region"
bucket_name = "bucket-test"
# 对象名称,例如 example_dir 下的 example_object.txt 文件,则填写为 example_dir/example_object.txt
object_key = "object-test"
try:
    # 创建 TosClientV2 对象,对桶和对象的操作都通过 TosClientV2 实现
    client = tos.TosClientV2(ak, sk, endpoint, region)
    # 创建类型为可追加文件,首次偏移 offset 设置为0
    # 通过 acl=tos.ACLType.ACL_Private 参数设置对象的访问权限为私有
    # 通过 storage_class=tos.StorageClassType.Storage_Class_Standard 设置对象的存储类型
    content_1 = b'Hello TOS A'
    content_2 = b'Hello TOS B'
    content_3 = b'Hello TOS C'

    # 追加数据, 偏移量从上次响应中获取<next_append_offset>,或者通过 head_object 返回的 content-length获取
    # 创建类型为可追加文件,首次偏移 offset 设置为0
    # 通过 acl=tos.ACLType.ACL_Private 参数设置对象的访问权限为私有
    # 通过 storage_class=tos.StorageClassType.Storage_Class_Standard 设置对象的存储类型
    # 第一次追加写入offset=0,无需设置pre_hash_crc64_ecma
    # 传入 pre_hash_crc64_ecma 保障了append对象数据完整性
    result_1 = client.append_object(bucket_name, object_key, 0, content=BytesIO(content_1), pre_hash_crc64_ecma=0)

    # 第二次追加, 偏移量从上次响应中获取<next_append_offset>,或者通过 head_object 返回的 content-length获取。
    # 设置offset=next_append_offset,设置pre_hash_crc64_ecma为上传响应中的hash_crc64_ecma
    # 传入 pre_hash_crc64_ecma 保障了append对象数据完整性
    result_2 = client.append_object(bucket_name, object_key, result_1.next_append_offset, content=BytesIO(content_2),
                                    pre_hash_crc64_ecma=result_1.hash_crc64_ecma)

    # 第三次次追加, 偏移量从上次响应中获取<next_append_offset>,或者通过 head_object 返回的 content-length获取。
    # 设置offset=next_append_offset,设置pre_hash_crc64_ecma为上传响应中的hash_crc64_ecma
    # 传入 pre_hash_crc64_ecma 保障了append对象数据完整性
    result_3 = client.append_object(bucket_name, object_key, result_2.next_append_offset, content=BytesIO(content_3),
                                    pre_hash_crc64_ecma=result_2.hash_crc64_ecma)
except tos.exceptions.TosClientError as e:
    # 操作失败,捕获客户端异常,一般情况为非法请求参数或网络异常
    print('fail with client error, message:{}, cause: {}'.format(e.message, e.cause))
except tos.exceptions.TosServerError as e:
    # 操作失败,捕获服务端异常,可从返回信息中获取详细错误信息
    print('fail with server error, code: {}'.format(e.code))
    # request id 可定位具体问题,强烈建议日志中保存
    print('error with request id: {}'.format(e.request_id))
    print('error with message: {}'.format(e.message))
    print('error with http code: {}'.format(e.status_code))
    print('error with ec: {}'.format(e.ec))
    print('error with request url: {}'.format(e.request_url))
except Exception as e:
    print('fail with unknown error: {}'.format(e))

追加上传网络流

以下代码用于将网络流追加上传到目标桶 bucket-test 中的 object-test 对象。

import requests
import os
import tos


# 从环境变量获取 AK 和 SK 信息。
ak = os.getenv('TOS_ACCESS_KEY')
sk = os.getenv('TOS_SECRET_KEY')
# your endpoint 和 your region 填写Bucket 所在区域对应的Endpoint。# 以华北2(北京)为例,your endpoint 填写 tos-cn-beijing.volces.com,your region 填写 cn-beijing。
endpoint = "your endpoint"
region = "your region"
bucket_name = "bucket-test"
# 对象名称,例如 example_dir 下的 example_object.txt 文件,则填写为 example_dir/example_object.txt
object_key = "object-test"
try:
    client = tos.TosClientV2(ak, sk, endpoint, region)
    next_append_offset = 0
    pre_hash_crc64_ecma = 0
    stream = requests.get('https://www.volcengine.com')
    for chunk in stream:
        # next_append_offset为偏移量,可从上次响应中获取<next_append_offset>,或者通过 head_object 返回的 <content-length>获取
        # pre_hash_crc64_ecma 当前数据的crc64值,可从上此响应中获取<hash_crc64_ecma>, 或通过head_object返回的 <hash_crc64_ecma>获取
        # 传入 pre_hash_crc64_ecma 保障了append对象数据完整性
        result = client.append_object(bucket_name, object_key, next_append_offset, content=chunk,
                                      pre_hash_crc64_ecma=pre_hash_crc64_ecma)
        next_append_offset = result.next_append_offset
        pre_hash_crc64_ecma = result.hash_crc64_ecma
    stream.close()
except tos.exceptions.TosClientError as e:
    # 操作失败,捕获客户端异常,一般情况为非法请求参数或网络异常
    print('fail with client error, message:{}, cause: {}'.format(e.message, e.cause))
except tos.exceptions.TosServerError as e:
    # 操作失败,捕获服务端异常,可从返回信息中获取详细错误信息
    print('fail with server error, code: {}'.format(e.code))
    # request id 可定位具体问题,强烈建议日志中保存
    print('error with request id: {}'.format(e.request_id))
    print('error with message: {}'.format(e.message))
    print('error with http code: {}'.format(e.status_code))
    print('error with ec: {}'.format(e.ec))
    print('error with request url: {}'.format(e.request_url))
except Exception as e:
    print('fail with unknown error: {}'.format(e))

进度条处理

说明

对于字符串、Bytes 和本地文件四种形式的数据,支持进度条功能。网络流等类型数据无法获取上传内容的大小,因此回调时不会返回对象总体大小。

以下代码用于向追加上传过程中添加进度条功能。

import os
import tos

from tos import DataTransferType

# 从环境变量获取 AK 和 SK 信息。
ak = os.getenv('TOS_ACCESS_KEY')
sk = os.getenv('TOS_SECRET_KEY')
# your endpoint 和 your region 填写Bucket 所在区域对应的Endpoint。# 以华北2(北京)为例,your endpoint 填写 tos-cn-beijing.volces.com,your region 填写 cn-beijing。
endpoint = "your endpoint"
region = "your region"
bucket_name = "bucket-test"
# 对象名称,例如 example_dir 下的 example_object.txt 文件,则填写为 example_dir/example_object.txt
object_key = "object-test"
try:
    def percentage(consumed_bytes: int, total_bytes: int, rw_once_bytes: int, type: DataTransferType):
        if total_bytes:
            rate = int(100 * float(consumed_bytes) / float(total_bytes))
            print("rate:{}, consumed_bytes:{},total_bytes{}, rw_once_bytes:{}, type:{}".format(rate, consumed_bytes,
                                                                                               total_bytes,
                                                                                               rw_once_bytes, type))


    client = tos.TosClientV2(ak, sk, endpoint, region)
    # data_transfer_listener 为可选参数, 用于实现进度条功能。
    client.append_object(bucket_name, object_key, 0, content='a' * 1024 * 1024, data_transfer_listener=percentage)
except tos.exceptions.TosClientError as e:
    # 操作失败,捕获客户端异常,一般情况为非法请求参数或网络异常
    print('fail with client error, message:{}, cause: {}'.format(e.message, e.cause))
except tos.exceptions.TosServerError as e:
    # 操作失败,捕获服务端异常,可从返回信息中获取详细错误信息
    print('fail with server error, code: {}'.format(e.code))
    # request id 可定位具体问题,强烈建议日志中保存
    print('error with request id: {}'.format(e.request_id))
    print('error with message: {}'.format(e.message))
    print('error with http code: {}'.format(e.status_code))
    print('error with ec: {}'.format(e.ec))
    print('error with request url: {}'.format(e.request_url))
except Exception as e:
    print('fail with unknown error: {}'.format(e))

客户端限速

以下代码用于追加上传过程中客户端限速。

import os
import tos


# 从环境变量获取 AK 和 SK 信息。
ak = os.getenv('TOS_ACCESS_KEY')
sk = os.getenv('TOS_SECRET_KEY')
# your endpoint 和 your region 填写Bucket 所在区域对应的Endpoint。# 以华北2(北京)为例,your endpoint 填写 tos-cn-beijing.volces.com,your region 填写 cn-beijing。
endpoint = "your endpoint"
region = "your region"
bucket_name = "bucket-test"
# 对象名称,例如 example_dir 下的 example_object.txt 文件,则填写为 example_dir/example_object.txt
object_key = "object-test"
try:
    client = tos.TosClientV2(ak, sk, endpoint, region)
    # rate_limiter 为可选参数, 用于实现客户端限速。
    # TOS Python SDK 通过最基本的令牌桶算法实现了客户端限速,其中rate为发送令牌的速率,capacity为总容量
    # 以下配置的意义为5mb/s的平均上传速率,最大支持 10 + 5 mb/s的上传速率
    rate_limiter = tos.RateLimiter(rate=1024 * 1024 * 5, capacity=10 * 1024 * 1024)
    client.append_object(bucket_name, object_key, 0, content='a' * 1024 * 1024, rate_limiter=rate_limiter)
except tos.exceptions.TosClientError as e:
    # 操作失败,捕获客户端异常,一般情况为非法请求参数或网络异常
    print('fail with client error, message:{}, cause: {}'.format(e.message, e.cause))
except tos.exceptions.TosServerError as e:
    # 操作失败,捕获服务端异常,可从返回信息中获取详细错误信息
    print('fail with server error, code: {}'.format(e.code))
    # request id 可定位具体问题,强烈建议日志中保存
    print('error with request id: {}'.format(e.request_id))
    print('error with message: {}'.format(e.message))
    print('error with http code: {}'.format(e.status_code))
    print('error with ec: {}'.format(e.ec))
    print('error with request url: {}'.format(e.request_url))
except Exception as e:
    print('fail with unknown error: {}'.format(e))

相关文档

关于追加上传的 API 文档,请参见 AppendObject

最近更新时间:2024.12.19 16:12:55
这个页面对您有帮助吗?
有用
有用
无用
无用