在上傳大文件(超過5 GB)到OSS的過程中,如果出現網絡中斷、程序異常退出等問題導致文件上傳失敗,您需要使用分片上傳的方式上傳大文件。分片上傳通過將待上傳的大文件分成多個較小的碎片(Part),充分利用網絡帶寬和服務器資源并發上傳多個Part,加快上傳完成時間,并在Part上傳完成之后調用CompleteMultipartUpload接口將這些Part組合成一個完整的Object。
注意事項
本文以華東1(杭州)外網Endpoint為例。如果您希望通過與OSS同地域的其他阿里云產品訪問OSS,請使用內網Endpoint。關于OSS支持的Region與Endpoint的對應關系,請參見OSS地域和訪問域名。
本文以從環境變量讀取訪問憑證為例。如何配置訪問憑證,請參見配置訪問憑證。
本文以OSS域名新建OSSClient為例。如果您希望通過自定義域名、STS等方式新建OSSClient,請參見初始化。
要分片上傳,您必須有
oss:PutObject
權限。具體操作,請參見為RAM用戶授權自定義的權限策略。
分片上傳流程
分片上傳(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方法將所有分片合并成完整的Object。
分片上傳完整示例
所有分片上傳完成后,您可以通過以下兩種方式將所有分片合并成完整的Object:
通過Body傳遞分片信息的方式將所有分片合并成完整的Object
# -*- coding: utf-8 -*- import os from oss2 import SizedFileAdapter, determine_part_size from oss2.models import PartInfo import oss2 from oss2.credentials import EnvironmentVariableCredentialsProvider # 從環境變量中獲取訪問憑證。運行本代碼示例之前,請確保已設置環境變量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。 auth = oss2.ProviderAuthV4(EnvironmentVariableCredentialsProvider()) # 填寫Bucket所在地域對應的Endpoint。以華東1(杭州)為例,Endpoint填寫為https://oss-cn-hangzhou.aliyuncs.com。 endpoint = "https://oss-cn-hangzhou.aliyuncs.com" # 填寫Endpoint對應的Region信息,例如cn-hangzhou。注意,v4簽名下,必須填寫該參數 region = "cn-hangzhou" # yourBucketName填寫存儲空間名稱。 bucket = oss2.Bucket(auth, endpoint, "yourBucketName", region=region) # 填寫不能包含Bucket名稱在內的Object完整路徑,例如exampledir/exampleobject.txt。 key = 'exampledir/exampleobject.txt' # 填寫本地文件的完整路徑,例如D:\\localpath\\examplefile.txt。 filename = 'D:\\localpath\\examplefile.txt' 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() # 指定該Object的網頁緩存行為。 # headers['Cache-Control'] = 'no-cache' # 指定該Object被下載時的名稱。 # headers['Content-Disposition'] = 'oss_MultipartUpload.txt' # 指定該Object的內容編碼格式。 # headers['Content-Encoding'] = 'utf-8' # 指定過期時間,單位為毫秒。 # headers['Expires'] = '1000' # 指定初始化分片上傳時是否覆蓋同名Object。此處設置為true,表示禁止覆蓋同名Object。 # headers['x-oss-forbid-overwrite'] = 'true' # 指定上傳該Object的每個Part時使用的服務器端加密方式。 # headers[OSS_SERVER_SIDE_ENCRYPTION] = SERVER_SIDE_ENCRYPTION_KMS # 指定Object的加密算法。如果未指定此選項,表明Object使用AES256加密算法。 # headers[OSS_SERVER_SIDE_DATA_ENCRYPTION] = SERVER_SIDE_ENCRYPTION_KMS # 表示KMS托管的用戶主密鑰。 # headers[OSS_SERVER_SIDE_ENCRYPTION_KEY_ID] = '9468da86-3509-4f8d-a61e-6eab1eac****' # 指定Object的存儲類型。 # headers['x-oss-storage-class'] = oss2.BUCKET_STORAGE_CLASS_STANDARD # 指定Object的對象標簽,可同時設置多個標簽。 # headers[OSS_OBJECT_TAGGING] = 'k1=v1&k2=v2&k3=v3' # upload_id = bucket.init_multipart_upload(key, headers=headers).upload_id upload_id = bucket.init_multipart_upload(key).upload_id # 根據upload_id執行取消分片上傳事件或者列舉已上傳分片的操作。 # 如果您需要根據您需要uploadId執行取消分片上傳事件的操作,您需要在調用InitiateMultipartUpload完成初始化分片之后獲取uploadId。 # 如果您需要根據您需要uploadId執行列舉已上傳分片的操作,您需要在調用InitiateMultipartUpload完成初始化分片之后,且在調用CompleteMultipartUpload完成分片上傳之前獲取uploadId。 # print("UploadID:", 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 # 完成分片上傳。 # 如需在完成分片上傳時設置相關Headers,請參考如下示例代碼。 headers = dict() # 設置文件訪問權限ACL。此處設置為OBJECT_ACL_PRIVATE,表示私有權限。 # 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)
重要網絡情況較好時,建議增大分片大小。反之,減小分片大小。
通過服務端List分片數據的方式合并成完整的Object
說明如果您希望使用該方式合并成完整Object,請確保已通過以下示例代碼中指定的upload_id上傳了多個分片。
# -*- coding: utf-8 -*- import oss2 from oss2.credentials import EnvironmentVariableCredentialsProvider # 從環境變量中獲取訪問憑證。運行本代碼示例之前,請確保已設置環境變量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。 auth = oss2.ProviderAuthV4(EnvironmentVariableCredentialsProvider()) # 填寫Bucket所在地域對應的Endpoint。以華東1(杭州)為例,Endpoint填寫為https://oss-cn-hangzhou.aliyuncs.com。 endpoint = "https://oss-cn-hangzhou.aliyuncs.com" # 填寫Endpoint對應的Region信息,例如cn-hangzhou。注意,v4簽名下,必須填寫該參數 region = "cn-hangzhou" # yourBucketName填寫存儲空間名稱。 bucket = oss2.Bucket(auth, endpoint, "yourBucketName", region=region) # 填寫不能包含Bucket名稱在內的Object完整路徑,例如exampledir/exampleobject.txt。 key = 'exampledir/exampleobject.txt' # 填寫本地文件的完整路徑,例如D:\\localpath\\examplefile.txt。 filename = 'D:\\localpath\\examplefile.txt' # 填寫upload_id。您需要在調用InitiateMultipartUpload完成初始化分片之后,且在調用CompleteMultipartUpload完成分片上傳之前獲取upload_id。 upload_id = '0004B9894A22E5B1888A1E29F823****' # 完成分片上傳。 # 如需在完成分片上傳時設置文件訪問權限ACL,請在complete_multipart_upload函數中設置相關headers,參考如下。 headers = dict() # headers["x-oss-object-acl"] = oss2.OBJECT_ACL_PRIVATE # 如果指定了x-oss-complete-all:yes,則OSS會列舉當前uploadId已上傳的所有Part,然后按照PartNumber的序號排序并執行CompleteMultipartUpload操作。 # 如果指定了x-oss-complete-all:yes,則不允許繼續指定Body,否則報錯。 headers["x-oss-complete-all"] = 'yes' bucket.complete_multipart_upload(key, upload_id, None, headers=headers)
取消分片上傳事件
您可以調用bucket.abort_multipart_upload方法來取消分片上傳事件。當一個分片上傳事件被取消后,無法再使用此uploadId做任何操作,已經上傳的分片數據會被刪除。
以下代碼用于取消分片上傳事件。
# -*- coding: utf-8 -*-
import os
import oss2
from oss2.credentials import EnvironmentVariableCredentialsProvider
# 從環境變量中獲取訪問憑證。運行本代碼示例之前,請確保已設置環境變量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
auth = oss2.ProviderAuthV4(EnvironmentVariableCredentialsProvider())
# 填寫Bucket所在地域對應的Endpoint。以華東1(杭州)為例,Endpoint填寫為https://oss-cn-hangzhou.aliyuncs.com。
endpoint = "https://oss-cn-hangzhou.aliyuncs.com"
# 填寫Endpoint對應的Region信息,例如cn-hangzhou。注意,v4簽名下,必須填寫該參數
region = "cn-hangzhou"
# yourBucketName填寫存儲空間名稱。
bucket = oss2.Bucket(auth, endpoint, "yourBucketName", region=region)
# 填寫不能包含Bucket名稱在內的Object完整路徑,例如exampledir/exampleobject.txt。
key = 'exampledir/exampleobject.txt'
# 填寫upload_id。upload_id來源于調用InitiateMultipartUpload完成初始化分片之后的返回結果。
upload_id = 'yourUploadId'
# 取消指定upload_id的分片上傳事件,已上傳的分片會被刪除。
bucket.abort_multipart_upload(key, upload_id)
列舉已上傳的分片信息
以下代碼用于列舉已上傳的分片信息:
# -*- coding: utf-8 -*-
import os
import oss2
from oss2.credentials import EnvironmentVariableCredentialsProvider
# 從環境變量中獲取訪問憑證。運行本代碼示例之前,請確保已設置環境變量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
auth = oss2.ProviderAuthV4(EnvironmentVariableCredentialsProvider())
# 填寫Bucket所在地域對應的Endpoint。以華東1(杭州)為例,Endpoint填寫為https://oss-cn-hangzhou.aliyuncs.com。
endpoint = "https://oss-cn-hangzhou.aliyuncs.com"
# 填寫Endpoint對應的Region信息,例如cn-hangzhou。注意,v4簽名下,必須填寫該參數
region = "cn-hangzhou"
# yourBucketName填寫存儲空間名稱。
bucket = oss2.Bucket(auth, endpoint, "yourBucketName", region=region)
# 填寫不能包含Bucket名稱在內的Object完整路徑,例如exampledir/exampleobject.txt。
key = 'exampledir/exampleobject.txt'
# 填寫upload_id。upload_id來源于調用InitiateMultipartUpload完成初始化分片之后,且在調用CompleteMultipartUpload完成分片上傳之前的返回結果。
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)
列舉分片上傳事件
列舉指定Object的分片上傳事件
以下代碼用于列舉指定Object的分片上傳事件:
# -*- coding: utf-8 -*- import os import oss2 from oss2.credentials import EnvironmentVariableCredentialsProvider # 從環境變量中獲取訪問憑證。運行本代碼示例之前,請確保已設置環境變量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。 auth = oss2.ProviderAuthV4(EnvironmentVariableCredentialsProvider()) # 填寫Bucket所在地域對應的Endpoint。以華東1(杭州)為例,Endpoint填寫為https://oss-cn-hangzhou.aliyuncs.com。 endpoint = "https://oss-cn-hangzhou.aliyuncs.com" # 填寫Endpoint對應的Region信息,例如cn-hangzhou。注意,v4簽名下,必須填寫該參數 region = "cn-hangzhou" # yourBucketName填寫存儲空間名稱。 bucket = oss2.Bucket(auth, endpoint, "yourBucketName", region=region) # 填寫不能包含Bucket名稱在內的Object完整路徑,例如exampledir/exampleobject.txt。 key = 'exampledir/exampleobject.txt' # 列舉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 from oss2.credentials import EnvironmentVariableCredentialsProvider # 阿里云賬號AccessKey擁有所有API的訪問權限,風險很高阿里云賬號AccessKey擁有所有API的訪問權限,風險很高。強烈建議您創建并使用RAM用戶進行API訪問或日常運維,請登錄RAM控制臺創建RAM用戶。 auth = oss2.ProviderAuthV4(EnvironmentVariableCredentialsProvider()) # 填寫Bucket所在地域對應的Endpoint。以華東1(杭州)為例,Endpoint填寫為https://oss-cn-hangzhou.aliyuncs.com。 endpoint = "https://oss-cn-hangzhou.aliyuncs.com" # 填寫Endpoint對應的Region信息,例如cn-hangzhou。注意,v4簽名下,必須填寫該參數 region = "cn-hangzhou" # yourBucketName填寫存儲空間名稱。 bucket = oss2.Bucket(auth, endpoint, "yourBucketName", region=region) # 列舉存儲空間下的所有分片上傳事件。 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 from oss2.credentials import EnvironmentVariableCredentialsProvider # 阿里云賬號AccessKey擁有所有API的訪問權限,風險很高阿里云賬號AccessKey擁有所有API的訪問權限,風險很高。強烈建議您創建并使用RAM用戶進行API訪問或日常運維,請登錄RAM控制臺創建RAM用戶。 auth = oss2.ProviderAuthV4(EnvironmentVariableCredentialsProvider()) # 填寫Bucket所在地域對應的Endpoint。以華東1(杭州)為例,Endpoint填寫為https://oss-cn-hangzhou.aliyuncs.com。 endpoint = "https://oss-cn-hangzhou.aliyuncs.com" # 填寫Endpoint對應的Region信息,例如cn-hangzhou。注意,v4簽名下,必須填寫該參數 region = "cn-hangzhou" # yourBucketName填寫存儲空間名稱。 bucket = oss2.Bucket(auth, endpoint, "yourBucketName", region=region) # 列舉存儲空間下以'test'為前綴的Object的分片上傳事件。 for upload_info in oss2.MultipartUploadIterator(bucket, prefix='test'): print('key:', upload_info.key) print('upload_id:', upload_info.upload_id)
常見問題
如何刪除碎片?
分片上傳過程被中斷后,已上傳的Part會一直保存在Bucket中。如果您不再需要這些Part,請通過以下方式刪除,以免產生額外的存儲費用。
相關文檔
分片上傳的完整實現涉及三個API接口,詳情如下:
關于初始化分片上傳事件的API接口說明,請參見InitiateMultipartUpload。
關于分片上傳Part的API接口說明,請參見UploadPart。
關于完成分片上傳的API接口說明,請參見CompleteMultipartUpload。
關于取消分片上傳事件的API接口說明,請參見AbortMultipartUpload。
關于列舉已上傳分片的API接口說明,請參見ListParts。
關于列舉所有執行中的分片上傳事件(即已完成初始化但未完成(Complete)或者未中止(Abort)的分片上傳事件)的API接口說明,請參見ListMultipartUploads。