全部產品
Search
文件中心

Object Storage Service:Python分區上傳

更新時間:Oct 25, 2024

在上傳大檔案(超過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)分為以下三個步驟:

  1. 初始化一個分區上傳事件。

    調用bucket.init_multipart_upload方法返回OSS建立的全域唯一的uploadId。

  2. 上傳分區。

    調用bucket.upload_part方法上傳分區資料。

    說明
    • 對於同一個uploadId,分區號(partNumber)標識了該分區在整個檔案內的相對位置。如果使用同一個分區號上傳了新的資料,那麼OSS上這個分區已有的資料將會被覆蓋。

    • OSS將收到的分區資料的MD5值放在ETag頭內返回給使用者。

    • OSS計算上傳資料的MD5值,並與SDK計算的MD5值比較,如果不一致則返回InvalidDigest錯誤碼。

  3. 完成分區上傳。

    所有分區上傳完成後,調用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,請通過以下方式刪除,以免產生額外的儲存費用。

  1. 手動刪除Part,請參見刪除片段

  2. 通過生命週期規則自動刪除Part,請參見設定生命週期規則

相關文檔

  • 分區上傳的完整實現涉及三個API介面,詳情如下:

  • 關於取消分區上傳事件的API介面說明,請參見AbortMultipartUpload

  • 關於列舉已上傳分區的API介面說明,請參見ListParts

  • 關於列舉所有執行中的分區上傳事件(即已完成初始化但未完成(Complete)或者未中止(Abort)的分區上傳事件)的API介面說明,請參見ListMultipartUploads