All Products
Search
Document Center

Object Storage Service:Unggah multi-bagian (Go SDK V1)

Last Updated:Mar 20, 2026

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:

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:

  1. Inisialisasi — Panggil Bucket.InitiateMultipartUpload. OSS akan mengembalikan ID unggah yang unik secara global.

  2. Unggah bagian — Panggil Bucket.UploadPart untuk 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 header ETag dan memvalidasinya terhadap hash yang dihitung oleh SDK. Jika tidak sesuai, OSS akan mengembalikan error InvalidDigest.

  3. Selesaikan — Panggil Bucket.CompleteMultipartUpload untuk 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?

Panggil Bucket.ListUploadedParts untuk melihat bagian mana saja yang telah berhasil diunggah untuk ID unggah tertentu. Ini berguna untuk memantau progres unggahan, mengidentifikasi bagian yang perlu diulang setelah kegagalan, atau mengelola penggunaan penyimpanan.

...
lsRes, err := bucket.ListUploadedParts(imur)
if err != nil {
    log.Fatalf("Gagal melihat daftar bagian yang diunggah: %v", err)
}

for _, upload := range lsRes.UploadedParts {
    log.Printf("PartNumber: %d, ETag: %s, LastModified: %v\n", upload.PartNumber, upload.ETag, upload.LastModified)
}

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:

ParameterDeskripsiDefault
DelimiterMengelompokkan nama objek yang memiliki awalan umum sebelum kemunculan pertama delimiter
MaxUploadsJumlah maksimum unggahan yang dikembalikan1000 (juga nilai maksimum)
KeyMarkerMengembalikan unggahan dengan nama objek yang secara leksikografis lebih besar dari nilai ini
PrefixHanya mengembalikan unggahan yang nama objeknya diawali dengan awalan ini
UploadIDMarkerDigunakan 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