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
}
常見問題
如何取消分片上傳事件?
當您遇到以下場景時,可以使用Bucket.AbortMultipartUpload
方法取消分片上傳事件。
文件出錯:
如果在上傳過程中發現文件有錯誤,如文件損壞或包含惡意代碼,您可以選擇取消上傳以避免潛在的風險。
網絡不穩定:
當網絡連接不穩定或中斷時,可能會導致上傳過程中的分片丟失或損壞,您可以選擇取消上傳并重新開始,以確保數據的完整性和一致性。
資源限制:
當您的存儲空間有限,而上傳的文件過大,您可以取消上傳以釋放存儲資源,將資源分配給其他更重要的任務。
誤操作:
當不小心啟動了一個不必要的上傳任務,或者上傳了一個錯誤的文件版本,您可以取消此次上傳事件
...
if err = bucket.AbortMultipartUpload(imur); err != nil {
log.Fatalf("failed to abort multipart upload: %w", err)
}
log.Printf("Multipart upload aborted successfully.")
如何列舉已上傳的分片?
當您遇到以下場景時,可以使用Bucket.ListUploadedParts
方法列舉某個分片上傳事件中已經成功上傳的分片。
監控上傳進度:
大型文件上傳:
當上傳非常大的文件時,您通過列舉已上傳的分片,確保上傳過程按照預期進行,并及時發現問題。
斷點續傳:
在網絡不穩定或上傳過程中發生中斷時,您可以通過查看已上傳的分片來決定是否需要重試上傳未完成的部分,從而實現斷點續傳。
故障排除:
如果上傳過程中出現錯誤,通過檢查已上傳的分片,您可以快速定位問題所在,比如某個特定分片上傳失敗,然后針對性地解決問題。
資源管理:
對于需要嚴格控制資源使用情況的場景,通過監控上傳進度,可以更好地管理存儲空間和帶寬資源,確保資源的有效利用。
...
if lsRes, err := bucket.ListUploadedParts(imur); err != nil {
log.Fatalf("Failed to list uploaded parts: %v", err)
}
for _, upload := range lsRes.UploadedParts {
log.Printf("List PartNumber: %d, ETag: %s, LastModified: %v\n", upload.PartNumber, upload.ETag, upload.LastModified)
}
列舉分片上傳事件
當您遇到以下場景時,可以使用Bucket.ListMultipartUploads
方法列舉某個存儲空間所有進行中的分片上傳事件。
監控場景:
批量文件上傳管理:
當需要上傳大量文件時,為了確保所有文件都能正確完成分片上傳,您可以使用
ListMultipartUploads
方法來實時監控所有的分片上傳活動。
故障檢測與恢復:
在上傳過程中如果遇到網絡問題或其他故障,可能導致部分分片未能成功上傳。通過監控正在進行中的分片上傳事件,可以及時發現這些問題,并采取措施恢復上傳。
資源優化與管理:
在大規模的文件上傳過程中,監控正在進行中的分片上傳事件可以幫助優化資源分配,例如根據上傳進度調整帶寬使用或優化上傳策略。
數據遷移:
在進行大規模的數據遷移項目時,監控所有正在進行的分片上傳事件可以確保遷移任務的順利進行,及時發現并解決任何潛在的問題。
參數設置
參數 | 說明 |
Delimiter | 用于對Object名字進行分組的字符。所有名字包含指定的前綴且第一次出現Delimiter字符之間的Object作為一組元素。 |
MaxUploads | 限定此次返回分片上傳事件的最大數目,默認值和最大值均為1000。 |
KeyMarker | 所有文件名稱的字母序大于KeyMarker參數值的分片上傳事件,可以與UploadIDMarker參數一同使用來指定返回結果的起始位置。 |
Prefix | 限定返回的文件名稱必須以指定的Prefix作為前綴。注意使用Prefix查詢時,返回的文件名稱中仍會包含Prefix。 |
UploadIDMarker | 與KeyMarker參數一同使用來指定返回結果的起始位置。
|
使用默認參數
... lsRes, err := bucket.ListMultipartUploads(oss.KeyMarker(keyMarker), oss.UploadIDMarker(uploadIdMarker)) if err != nil { log.Fatalf("failed to list multipart uploads: %w", err) } for _, upload := range lsRes.Uploads { log.Printf("Upload: %s, UploadID: %s\n", upload.Key, upload.UploadID) }
指定前綴為file
... lsRes, err := bucket.ListMultipartUploads(oss.Prefix('file')) if err != nil { log.Fatalf("failed to list multipart uploads with prefix: %w", err) } log.Printf("Uploads:", lsRes.Uploads)
指定最多返回100條結果數據
... lsRes, err := bucket.ListMultipartUploads(oss.MaxUploads(100)) if err != nil { log.Fatalf("failed to list multipart uploads with limit: %w", err) } log.Printf("Uploads:", lsRes.Uploads)
指定前綴為file且最多返回100條結果數據
... lsRes, err := bucket.ListMultipartUploads(oss.Prefix("file"), oss.MaxUploads(100)) if err != nil { log.Fatalf("failed to list multipart uploads with prefix and limit: %w", err) } log.Printf("Uploads:", lsRes.Uploads)
相關文檔
關于分片上傳的完整示例代碼,請參見GitHub示例。
分片上傳的完整實現涉及三個API接口,詳情如下:
關于初始化分片上傳事件的API接口說明,請參見InitiateMultipartUpload。
關于分片上傳Part的API接口說明,請參見UploadPart。
關于完成分片上傳的API接口說明,請參見CompleteMultipartUpload。
關于取消分片上傳事件的API接口說明,請參見AbortMultipartUpload。
關于列舉已上傳分片的API接口說明,請參見ListUploadedParts。
關于列舉所有執行中的分片上傳事件(即已初始化但尚未完成或已取消的分片上傳事件)的API接口說明,請參見ListMultipartUploads。