OSS提供的分區上傳(Multipart Upload)功能,將要上傳的較大檔案(Object)分成多個分區(Part)來分別上傳,上傳完成後再調用CompleteMultipartUpload介面將這些Part組合成一個Object來達到斷點續傳的效果。
注意事項
本文以華東1(杭州)外網Endpoint為例。如果您希望通過與OSS同地區的其他阿里雲產品訪問OSS,請使用內網Endpoint。關於OSS支援的Region與Endpoint的對應關係,請參見OSS訪問網域名稱、資料中心、開放連接埠。
本文以從環境變數讀取存取憑證為例。如何配置訪問憑證,請參見配置訪問憑證。
本文以OSS網域名稱建立OSSClient為例。如果您希望通過自訂網域名、STS等方式建立OSSClient,請參見初始化。
要分區上傳,您必須有
oss:PutObject
許可權。具體操作,請參見為RAM使用者授權自訂的權限原則。Go SDK 2.2.5及以上版本支援以下範例程式碼中包含的所有屬性。
分區上傳流程
分區上傳(Multipart Upload)分為以下三個步驟:
初始化一個分區上傳事件。
調用Bucket.InitiateMultipartUpload方法返回OSS建立的全域唯一的uploadID。
上傳分區。
調用Bucket.UploadPart方法上傳分區資料。
說明對於同一個uploadID,分區號(partNumber)標識了該分區在整個檔案內的相對位置。如果使用同一個分區號上傳了新的資料,那麼OSS上該分區已有的資料將會被覆蓋。
OSS將收到的分區資料的MD5值放在ETag頭內返回給使用者。
OSS計算上傳資料的MD5值,並與SDK計算的MD5值比較,如果不一致則返回InvalidDigest錯誤碼。
完成分區上傳。
所有分區上傳完成後,調用Bucket.CompleteMultipartUpload方法將所有分區合并成完整的檔案。
範例程式碼
您可以使用以下代碼進行一次完整的分區上傳流程。
package main
import (
"fmt"
"log"
"os"
"github.com/aliyun/aliyun-oss-go-sdk/oss"
)
func main() {
// 從環境變數中擷取訪問憑證。運行本程式碼範例之前,請確保已設定環境變數OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
provider, err := oss.NewEnvironmentVariableCredentialsProvider()
if err != nil {
log.Fatalf("Error: %v", err)
}
// 建立OSSClient執行個體。
// yourEndpoint填寫Bucket對應的Endpoint,以華東1(杭州)為例,填寫為https://oss-cn-hangzhou.aliyuncs.com。其它Region請按實際情況填寫。
// yourRegion填寫Bucket所在地區,以華東1(杭州)為例,填寫為cn-hangzhou。其它Region請按實際情況填寫。
clientOptions := []oss.ClientOption{oss.SetCredentialsProvider(&provider)}
clientOptions = append(clientOptions, oss.Region("yourRegion"))
// 設定簽名版本
clientOptions = append(clientOptions, oss.AuthVersion(oss.AuthV4))
client, err := oss.New("yourEndpoint", "", "", clientOptions...)
if err != nil {
log.Fatalf("Error: %v", err)
}
// 設定儲存空間名稱
bucketName := "examplebucket"
// 設定Object完整路徑。Object完整路徑中不能包含Bucket名稱。
objectName := "exampleobject.txt"
// 設定本地檔案的完整路徑。如果未指定本地路徑,則預設從樣本程式所屬專案對應本地路徑中上傳檔案。
localFilename := "/localpath/exampleobject.txt"
bucket, err := client.Bucket(bucketName)
if err != nil {
log.Fatalf("Error: %v", err)
}
// 設定分區大小(單位:位元組),指定5MB為分區大小。
partSize := int64(5 * 1024 * 1024)
// 調用分區上傳函數。
if err := uploadMultipart(bucket, objectName, localFilename, partSize); err != nil {
log.Fatalf("Failed to upload multipart: %v", err)
}
}
// 分區上傳函數
func uploadMultipart(bucket *oss.Bucket, objectName, localFilename string, partSize int64) error {
// 將本地檔案分區
chunks, err := oss.SplitFileByPartSize(localFilename, partSize)
if err != nil {
return fmt.Errorf("failed to split file into chunks: %w", err)
}
// 開啟本地檔案。
file, err := os.Open(localFilename)
if err != nil {
return fmt.Errorf("failed to open file: %w", err)
}
defer file.Close()
// 步驟1:初始化一個分區上傳事件。
imur, err := bucket.InitiateMultipartUpload(objectName)
if err != nil {
return fmt.Errorf("failed to initiate multipart upload: %w", err)
}
// 步驟2:上傳分區。
var parts []oss.UploadPart
for _, chunk := range chunks {
part, err := bucket.UploadPart(imur, file, chunk.Size, chunk.Number)
if err != nil {
// 如果上傳某個部分失敗,嘗試取消整個上傳任務。
if abortErr := bucket.AbortMultipartUpload(imur); abortErr != nil {
log.Printf("Failed to abort multipart upload: %v", abortErr)
}
return fmt.Errorf("failed to upload part: %w", err)
}
parts = append(parts, part)
}
// 指定Object的讀寫權限為私人,預設為繼承Bucket的讀寫權限。
objectAcl := oss.ObjectACL(oss.ACLPrivate)
// 步驟3:完成分區上傳。
_, err = bucket.CompleteMultipartUpload(imur, parts, objectAcl)
if err != nil {
// 如果完成上傳失敗,嘗試取消上傳。
if abortErr := bucket.AbortMultipartUpload(imur); abortErr != nil {
log.Printf("Failed to abort multipart upload: %v", abortErr)
}
return fmt.Errorf("failed to complete multipart upload: %w", err)
}
log.Printf("Multipart upload completed successfully.")
return nil
}
常見問題
如何取消分區上傳事件?
如何列舉已上傳的分區?
列舉分區上傳事件
相關文檔
關於分區上傳的完整範例程式碼,請參見GitHub樣本。
分區上傳的完整實現涉及三個API介面,詳情如下:
關於初始化分區上傳事件的API介面說明,請參見InitiateMultipartUpload。
關於分區上傳Part的API介面說明,請參見UploadPart。
關於完成分區上傳的API介面說明,請參見CompleteMultipartUpload。
關於取消分區上傳事件的API介面說明,請參見AbortMultipartUpload。
關於列舉已上傳分區的API介面說明,請參見ListUploadedParts。
關於列舉所有執行中的分區上傳事件(即已初始化但尚未完成或已取消的分區上傳事件)的API介面說明,請參見ListMultipartUploads。