OSS提供的分片上传(Multipart Upload)功能,将要上传的较大文件(Object)分成多个数据块(Part)来分别上传,上传完成后再调用CompleteMultipartUpload接口将这些Part组合成一个Object来达到断点续传的效果。
分片上传流程
分片上传(Multipart Upload)分为以下三个步骤:
- 初始化一个分片上传事件。
调用bucket.init_multipart_upload方法返回OSS创建的全局唯一的uploadId。
- 上传分片。
调用bucket.upload_part方法上传分片数据。
说明- 对于同一个uploadId,分片号(partNumber)标识了该分片在整个文件内的相对位置。如果使用同一个分片号上传了新的数据,那么OSS上这个分片已有的数据将会被覆盖。
- OSS将收到的分片数据的MD5值放在ETag头内返回给用户。
- OSS计算上传数据的MD5值,并与SDK计算的MD5值比较,如果不一致则返回InvalidDigest错误码。
- 完成分片上传。
所有分片上传完成后,调用bucket.complete_multipart_upload方法将所有分片合并成完整的文件。
分片上传完整示例
以下通过一个完整的示例对分片上传的流程进行逐步解析:
# -*- coding: utf-8 -*- import os from oss2 import SizedFileAdapter, determine_part_size from oss2.models import PartInfo import oss2 # 阿里云主账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM账号进行API访问或日常运维,请登录RAM控制台创建RAM账号。 auth = oss2.Auth('<yourAccessKeyId>', '<yourAccessKeySecret>') # Endpoint以杭州为例,其它Region请按实际情况填写。 bucket = oss2.Bucket(auth, 'http://oss-cn-hangzhou.aliyuncs.com', '<yourBucketName>') key = '<yourObjectName>' filename = '<yourLocalFile>' total_size = os.path.getsize(filename) # determine_part_size方法用于确定分片大小。 part_size = determine_part_size(total_size, preferred_size=100 * 1024) # 初始化分片。 # 如需在初始化分片时设置文件存储类型,请在init_multipart_upload中设置相关headers,参考如下。 # headers = dict() # headers["x-oss-storage-class"] = "Standard" # upload_id = bucket.init_multipart_upload(key, headers=headers).upload_id upload_id = bucket.init_multipart_upload(key).upload_id parts = [] # 逐个上传分片。 with open(filename, 'rb') as fileobj: part_number = 1 offset = 0 while offset < total_size: num_to_upload = min(part_size, total_size - offset) # 调用SizedFileAdapter(fileobj, size)方法会生成一个新的文件对象,重新计算起始追加位置。 result = bucket.upload_part(key, upload_id, part_number, SizedFileAdapter(fileobj, num_to_upload)) parts.append(PartInfo(part_number, result.etag)) offset += num_to_upload part_number += 1 # 完成分片上传。 # 如需在完成分片上传时设置文件访问权限ACL,请在complete_multipart_upload函数中设置相关headers,参考如下。 # headers = dict() # headers["x-oss-object-acl"] = oss2.OBJECT_ACL_PRIVATE # bucket.complete_multipart_upload(key, upload_id, parts, headers=headers) bucket.complete_multipart_upload(key, upload_id, parts) # 验证分片上传。 with open(filename, 'rb') as fileobj: assert bucket.get_object(key).read() == fileobj.read()
说明 网络情况较好时,建议增大分片大小。反之,减小分片大小。
有关分片上传的更多详情,请参见InitiateMultipartUpload以及CompleteMultipartUpload。
取消分片上传事件
您可以调用bucket.abort_multipart_upload方法来取消分片上传事件。当一个分片上传事件被取消后,无法再使用此uploadId做任何操作,已经上传的分片数据会被删除。
以下代码用于取消分片上传事件:
# -*- coding: utf-8 -*- import os import oss2 # 阿里云主账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM账号进行API访问或日常运维,请登录RAM控制台创建RAM账号。 auth = oss2.Auth('<yourAccessKeyId>', '<yourAccessKeySecret>') # Endpoint以杭州为例,其它Region请按实际情况填写。 bucket = oss2.Bucket(auth, 'http://oss-cn-hangzhou.aliyuncs.com', '<yourBucketName>') key = '<yourObjectName>' # 由init_multipart_upload接口返回的upload_id。 upload_id = '<yourUploadId>' # 取消指定upload_id的分片上传事件,已上传的分片会被删除。 bucket.abort_multipart_upload(key, upload_id)
取消分片上传事件的更多详情,请参见AbortMultipartUpload。
列举已上传的分片信息
以下代码用于列举已上传的分片信息:
# -*- coding: utf-8 -*- import os import oss2 # 阿里云主账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM账号进行API访问或日常运维,请登录RAM控制台创建RAM账号。 auth = oss2.Auth('<yourAccessKeyId>', '<yourAccessKeySecret>') # Endpoint以杭州为例,其它Region请按实际情况填写。 bucket = oss2.Bucket(auth, 'http://oss-cn-hangzhou.aliyuncs.com', '<yourBucketName>') key = '<yourObjectName>' # 由init_multipart_upload接口返回的upload_id。 upload_id = '<yourUploadId>' # 列举指定upload_id对应的已上传分片信息。 for part_info in oss2.PartIterator(bucket, key, upload_id): print('part_number:', part_info.part_number) print('etag:', part_info.etag) print('size:', part_info.size)
列举已上传分片的更多详情,请参见ListParts。
列举分片上传事件
- 列举指定Object的分片上传事件
以下代码用于列举指定Object的分片上传事件:
# -*- coding: utf-8 -*- import os import oss2 # 阿里云主账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM账号进行API访问或日常运维,请登录RAM控制台创建RAM账号。 auth = oss2.Auth('<yourAccessKeyId>', '<yourAccessKeySecret>') # Endpoint以杭州为例,其它Region请按实际情况填写。 bucket = oss2.Bucket(auth, 'http://oss-cn-hangzhou.aliyuncs.com', '<yourBucketName>') key = '<yourObjectName>' # 列举Object的所有分片上传事件。对于同一个Object,每次调用init_multipart_upload均会返回不同的upload_id。 # 一个upload_id对应一个分片上传事件。 for upload_info in oss2.ObjectUploadIterator(bucket, key): print('key:', upload_info.key) print('upload_id:', upload_info.upload_id)
- 列举存储空间下的所有分片事件
以下代码用于列举存储空间下的所有分片上传事件:
# -*- coding: utf-8 -*- import os import oss2 # 阿里云主账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM账号进行API访问或日常运维,请登录RAM控制台创建RAM账号。 auth = oss2.Auth('<yourAccessKeyId>', '<yourAccessKeySecret>') # Endpoint以杭州为例,其它Region请按实际情况填写。 bucket = oss2.Bucket(auth, 'http://oss-cn-hangzhou.aliyuncs.com', '<yourBucketName>') # 列举存储空间下的所有分片上传事件。 for upload_info in oss2.MultipartUploadIterator(bucket): print('key:', upload_info.key) print('upload_id:', upload_info.upload_id)
- 列举存储空间下指定前缀Object的分片上传事件
以下代码用于列举存储空间下指定前缀Object的分片上传事件:
# -*- coding: utf-8 -*- import os import oss2 # 阿里云主账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM账号进行API访问或日常运维,请登录RAM控制台创建RAM账号。 auth = oss2.Auth('<yourAccessKeyId>', '<yourAccessKeySecret>') # Endpoint以杭州为例,其它Region请按实际情况填写。 bucket = oss2.Bucket(auth, 'http://oss-cn-hangzhou.aliyuncs.com', '<yourBucketName>') # 列举存储空间下以'test'为前缀的Object的分片上传事件。 for upload_info in oss2.MultipartUploadIterator(bucket, prefix='test'): print('key:', upload_info.key) print('upload_id:', upload_info.upload_id)
列举分片上传事件的更多详情,请参见ListMultipartUploads。