在上傳大檔案(超過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。