Gunakan unggah multi-bagian untuk mengunggah objek besar ke OSS secara bertahap. Anda dapat mengunggah bagian-bagian tersebut secara paralel guna meningkatkan throughput, melanjutkan unggahan yang terputus tanpa memulai dari awal, serta memulai pengunggahan sebelum mengetahui ukuran akhir objek.
Prasyarat
Sebelum memulai, pastikan Anda telah:
Menginstal Go SDK V2.2.5 atau versi yang lebih baru.
Memiliki izin
oss:PutObjectpada bucket Anda. Lihat Lampirkan kebijakan kustom ke RAM user.Menyetel variabel lingkungan
OSS_ACCESS_KEY_IDdanOSS_ACCESS_KEY_SECRET. Lihat Konfigurasikan kredensial akses.Membuat instans OSSClient. Lihat Konfigurasikan instans OSSClient.
Contoh dalam topik ini menggunakan titik akhir publik untuk wilayah China (Hangzhou). Jika aplikasi dan bucket OSS Anda berada di wilayah yang sama, gunakan titik akhir internal untuk menghindari biaya transfer data. Lihat Wilayah dan titik akhir.
Cara kerja
Unggah multi-bagian mencakup tiga langkah:
Inisialisasi — Panggil
Bucket.InitiateMultipartUpload. OSS akan mengembalikan ID unggah yang unik secara global.Unggah bagian — Panggil
Bucket.UploadPartuntuk setiap bagian, yang diidentifikasi oleh nomor bagian yang menentukan posisinya dalam objek akhir. Mengunggah bagian baru dengan nomor bagian yang sama akan menimpa bagian yang sudah ada. OSS mengembalikan hash MD5 dari setiap bagian yang diterima dalam headerETagdan memvalidasinya terhadap hash yang dihitung oleh SDK. Jika tidak sesuai, OSS akan mengembalikan errorInvalidDigest.Selesaikan — Panggil
Bucket.CompleteMultipartUploaduntuk menggabungkan semua bagian yang diunggah menjadi satu objek.
Unggah objek secara bertahap
Contoh berikut mengunggah file lokal menggunakan unggah multi-bagian dengan ukuran bagian 5 MiB.
package main
import (
"fmt"
"log"
"os"
"github.com/aliyun/aliyun-oss-go-sdk/oss"
)
func main() {
// Dapatkan kredensial akses dari variabel lingkungan. Sebelum menjalankan kode contoh,
// pastikan variabel lingkungan OSS_ACCESS_KEY_ID dan OSS_ACCESS_KEY_SECRET telah dikonfigurasi.
provider, err := oss.NewEnvironmentVariableCredentialsProvider()
if err != nil {
log.Fatalf("Error: %v", err)
}
// Buat instans OSSClient.
// Setel yourEndpoint ke titik akhir bucket. Misalnya, untuk bucket di wilayah
// China (Hangzhou), setel titik akhir ke https://oss-cn-hangzhou.aliyuncs.com.
// Setel yourRegion ke wilayah tempat bucket berada. Misalnya, cn-hangzhou.
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"
objectName := "exampleobject.txt"
// Jika tidak ada path lokal yang ditentukan, file dibaca dari direktori program contoh.
localFilename := "/localpath/exampleobject.txt"
bucket, err := client.Bucket(bucketName)
if err != nil {
log.Fatalf("Error: %v", err)
}
// Setel ukuran bagian menjadi 5 MiB.
partSize := int64(5 * 1024 * 1024)
if err := uploadMultipart(bucket, objectName, localFilename, partSize); err != nil {
log.Fatalf("Gagal mengunggah multi-bagian: %v", err)
}
}
func uploadMultipart(bucket *oss.Bucket, objectName, localFilename string, partSize int64) error {
// Pisahkan file lokal menjadi bagian-bagian berdasarkan ukuran bagian yang ditentukan.
chunks, err := oss.SplitFileByPartSize(localFilename, partSize)
if err != nil {
return fmt.Errorf("gagal memisahkan file menjadi chunk: %w", err)
}
file, err := os.Open(localFilename)
if err != nil {
return fmt.Errorf("gagal membuka file: %w", err)
}
defer file.Close()
// Langkah 1: Inisialisasi unggah multi-bagian. OSS mengembalikan ID unggah unik.
imur, err := bucket.InitiateMultipartUpload(objectName)
if err != nil {
return fmt.Errorf("gagal menginisialisasi unggah multi-bagian: %w", err)
}
// Langkah 2: Unggah setiap bagian. Nomor chunk menentukan posisi bagian dalam objek akhir.
var parts []oss.UploadPart
for _, chunk := range chunks {
part, err := bucket.UploadPart(imur, file, chunk.Size, chunk.Number)
if err != nil {
// Batalkan unggahan untuk melepaskan ruang penyimpanan dari bagian yang telah diunggah.
if abortErr := bucket.AbortMultipartUpload(imur); abortErr != nil {
log.Printf("Gagal membatalkan unggah multi-bagian: %v", abortErr)
}
return fmt.Errorf("gagal mengunggah bagian: %w", err)
}
parts = append(parts, part)
}
// Setel ACL objek menjadi private. Secara default, objek mewarisi ACL bucket.
objectAcl := oss.ObjectACL(oss.ACLPrivate)
// Langkah 3: Selesaikan unggah multi-bagian dengan menggabungkan semua bagian yang diunggah.
_, err = bucket.CompleteMultipartUpload(imur, parts, objectAcl)
if err != nil {
if abortErr := bucket.AbortMultipartUpload(imur); abortErr != nil {
log.Printf("Gagal membatalkan unggah multi-bagian: %v", abortErr)
}
return fmt.Errorf("gagal menyelesaikan unggah multi-bagian: %w", err)
}
log.Printf("Unggah multi-bagian berhasil diselesaikan.")
return nil
}FAQ
Bagaimana cara membatalkan unggah multi-bagian?
Panggil Bucket.AbortMultipartUpload untuk menghentikan unggah multi-bagian dan melepaskan ruang penyimpanan untuk semua bagian yang telah diunggah. Batalkan unggahan jika file rusak, jaringan tidak andal, ruang penyimpanan terbatas, atau unggahan dimulai secara tidak sengaja.
...
if err = bucket.AbortMultipartUpload(imur); err != nil {
log.Fatalf("gagal membatalkan unggah multi-bagian: %v", err)
}
log.Printf("Unggah multi-bagian berhasil dibatalkan.")Bagaimana cara melihat daftar bagian yang telah diunggah?
Bagaimana cara melihat daftar semua unggah multi-bagian yang sedang berlangsung di suatu bucket?
Panggil Bucket.ListMultipartUploads untuk melihat semua unggah multi-bagian yang telah dimulai tetapi belum diselesaikan atau dibatalkan. Gunakan ini untuk memantau unggahan batch, mendeteksi unggahan yang macet, atau mengidentifikasi unggahan yang perlu dibersihkan.
Parameter berikut memungkinkan Anda memfilter dan membagi hasil:
| Parameter | Deskripsi | Default |
|---|---|---|
Delimiter | Mengelompokkan nama objek yang memiliki awalan umum sebelum kemunculan pertama delimiter | — |
MaxUploads | Jumlah maksimum unggahan yang dikembalikan | 1000 (juga nilai maksimum) |
KeyMarker | Mengembalikan unggahan dengan nama objek yang secara leksikografis lebih besar dari nilai ini | — |
Prefix | Hanya mengembalikan unggahan yang nama objeknya diawali dengan awalan ini | — |
UploadIDMarker | Digunakan bersama KeyMarker: mengembalikan unggahan dengan nama objek yang sama tetapi ID unggah lebih besar dari nilai ini. Diabaikan jika KeyMarker tidak disetel | — |
Gunakan parameter default:
...
lsRes, err := bucket.ListMultipartUploads(oss.KeyMarker(keyMarker), oss.UploadIDMarker(uploadIdMarker))
if err != nil {
log.Fatalf("gagal melihat daftar unggah multi-bagian: %v", err)
}
for _, upload := range lsRes.Uploads {
log.Printf("Key: %s, UploadID: %s\n", upload.Key, upload.UploadID)
}Filter berdasarkan awalan:
...
lsRes, err := bucket.ListMultipartUploads(oss.Prefix("file"))
if err != nil {
log.Fatalf("gagal melihat daftar unggah multi-bagian dengan awalan: %v", err)
}
log.Printf("Unggahan: %v", lsRes.Uploads)Batasi jumlah hasil:
...
lsRes, err := bucket.ListMultipartUploads(oss.MaxUploads(100))
if err != nil {
log.Fatalf("gagal melihat daftar unggah multi-bagian dengan batasan: %v", err)
}
log.Printf("Unggahan: %v", lsRes.Uploads)Gabungkan awalan dan batasan:
...
lsRes, err := bucket.ListMultipartUploads(oss.Prefix("file"), oss.MaxUploads(100))
if err != nil {
log.Fatalf("gagal melihat daftar unggah multi-bagian dengan awalan dan batasan: %v", err)
}
log.Printf("Unggahan: %v", lsRes.Uploads)Langkah selanjutnya
Untuk kode contoh lengkap, lihat contoh di GitHub.