全部产品
Search
文档中心

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

更新时间:Nov 09, 2025

Object Storage Service (OSS) menyediakan fitur unggah multi-bagian yang memungkinkan Anda mengunggah objek besar dalam beberapa bagian. Setelah semua bagian diunggah, Anda dapat memanggil operasi CompleteMultipartUpload untuk menggabungkannya menjadi satu objek lengkap.

Catatan

  • Kode contoh dalam topik ini menggunakan ID Wilayah cn-hangzhou dari Wilayah (Hangzhou) Tiongkok. Secara default, titik akhir publik digunakan untuk mengakses sumber daya dalam bucket. Jika Anda ingin mengakses sumber daya bucket dari layanan Alibaba Cloud lainnya di wilayah yang sama, gunakan titik akhir internal. Untuk informasi lebih lanjut tentang Wilayah dan titik akhir OSS, lihat Wilayah dan titik akhir.

  • Dalam topik ini, kredensial akses diperoleh dari variabel lingkungan. Untuk informasi lebih lanjut tentang cara mengonfigurasi kredensial akses, lihat Konfigurasikan Kredensial Akses.

  • Untuk menggunakan unggah multi-bagian, Anda harus memiliki izin oss:PutObject. Untuk informasi lebih lanjut, lihat Lampirkan kebijakan kustom ke Pengguna RAM.

Proses unggah multi-bagian

Unggah multi-bagian melibatkan tiga langkah berikut:

  1. Mulai peristiwa unggah multi-bagian.

    Panggil metode Client.InitiateMultipartUpload untuk mendapatkan ID unggah unik secara global yang dibuat oleh OSS.

  2. Unggah bagian-bagian.

    Panggil metode Client.UploadPart untuk mengunggah data bagian.

    Catatan
    • Untuk ID unggah tertentu, nomor bagian mengidentifikasi posisi sebuah bagian dalam objek lengkap. Jika Anda menggunakan nomor bagian yang sama untuk mengunggah data baru, data bagian yang ada di OSS akan ditimpa.

    • OSS menyertakan hash MD5 dari data bagian yang diterima dalam header ETag yang dikembalikan kepada pengguna.

    • OSS menghitung hash MD5 dari data yang diunggah dan membandingkannya dengan hash MD5 yang dihitung oleh SDK. Jika kedua hash MD5 berbeda, kode kesalahan InvalidDigest dikembalikan.

  3. Selesaikan unggah multi-bagian.

    Setelah semua bagian diunggah, panggil metode Client.CompleteMultipartUpload untuk menggabungkan bagian-bagian menjadi satu objek lengkap.

Contoh

Kode contoh berikut menunjukkan cara membagi file lokal besar menjadi beberapa bagian, mengunggah bagian-bagian tersebut ke bucket secara bersamaan, lalu menggabungkan bagian-bagian tersebut menjadi satu objek lengkap.

package main

import (
	"bufio"
	"bytes"
	"context"
	"flag"
	"io"
	"log"
	"os"
	"sync"

	"github.com/aliyun/alibabacloud-oss-go-sdk-v2/oss"
	"github.com/aliyun/alibabacloud-oss-go-sdk-v2/oss/credentials"
)

// Tentukan variabel global.
var (
	region     string // Wilayah.
	bucketName string // Nama bucket sumber.
	objectName string // Nama objek sumber.

)

// Fungsi init digunakan untuk menginisialisasi parameter baris perintah.
func init() {
	flag.StringVar(&region, "region", "", "Wilayah tempat bucket berada.")
	flag.StringVar(&bucketName, "bucket", "", "Nama bucket sumber.")
	flag.StringVar(&objectName, "object", "", "Nama objek sumber.")
}

func main() {
	// Parsing parameter baris perintah.
	flag.Parse()

	// Tentukan ID unggah.
	var uploadId string

	// Periksa apakah nama bucket sumber kosong.
	if len(bucketName) == 0 {
		flag.PrintDefaults()
		log.Fatalf("parameter tidak valid, nama bucket sumber diperlukan")
	}

	// Periksa apakah wilayah kosong.
	if len(region) == 0 {
		flag.PrintDefaults()
		log.Fatalf("parameter tidak valid, wilayah diperlukan")
	}

	// Periksa apakah nama objek sumber kosong.
	if len(objectName) == 0 {
		flag.PrintDefaults()
		log.Fatalf("parameter tidak valid, nama objek sumber diperlukan")
	}

	// Muat konfigurasi default, dan atur penyedia kredensial dan wilayah.
	cfg := oss.LoadDefaultConfig().
		WithCredentialsProvider(credentials.NewEnvironmentVariableCredentialsProvider()).
		WithRegion(region)

	// Buat klien OSS.
	client := oss.NewClient(cfg)

	// Mulai permintaan unggah multi-bagian.
	initRequest := &oss.InitiateMultipartUploadRequest{
		Bucket: oss.Ptr(bucketName),
		Key:    oss.Ptr(objectName),
	}
	initResult, err := client.InitiateMultipartUpload(context.TODO(), initRequest)
	if err != nil {
		log.Fatalf("gagal memulai unggah multi-bagian %v", err)
	}

	// Cetak hasil memulai unggah multi-bagian.
	log.Printf("hasil inisiasi unggah multi-bagian:%#v\n", *initResult.UploadId)
	uploadId = *initResult.UploadId

	// Inisialisasi wait group dan mutex.
	var wg sync.WaitGroup
	var parts []oss.UploadPart
	count := 3
	var mu sync.Mutex

	// Baca konten file lokal ke dalam memori. Ganti yourLocalFile dengan nama dan jalur file lokal sebenarnya.
	file, err := os.Open("yourLocalFile")
	if err != nil {
		log.Fatalf("gagal membuka file lokal %v", err)
	}
	defer file.Close()

	bufReader := bufio.NewReader(file)
	content, err := io.ReadAll(bufReader)
	if err != nil {
		log.Fatalf("gagal membaca file lokal %v", err)
	}
	log.Printf("ukuran file: %d\n", len(content))

	// Hitung ukuran setiap bagian.
	chunkSize := len(content) / count
	if chunkSize == 0 {
		chunkSize = 1
	}

	// Mulai beberapa goroutine untuk mengunggah bagian.
	for i := 0; i < count; i++ {
		start := i * chunkSize
		end := start + chunkSize
		if i == count-1 {
			end = len(content)
		}

		wg.Add(1)
		go func(partNumber int, start, end int) {
			defer wg.Done()

			// Buat permintaan untuk mengunggah bagian.
			partRequest := &oss.UploadPartRequest{
				Bucket:     oss.Ptr(bucketName),                 // Nama bucket tujuan.
				Key:        oss.Ptr(objectName),                 // Nama objek tujuan.
				PartNumber: int32(partNumber),                   // Nomor bagian.
				UploadId:   oss.Ptr(uploadId),                   // ID unggah.
				Body:       bytes.NewReader(content[start:end]), // Konten bagian.
			}

			// Kirim permintaan untuk mengunggah bagian.
			partResult, err := client.UploadPart(context.TODO(), partRequest)
			if err != nil {
				log.Fatalf("gagal mengunggah bagian %d: %v", partNumber, err)
			}

			// Catat hasil unggah bagian.
			part := oss.UploadPart{
				PartNumber: partRequest.PartNumber,
				ETag:       partResult.ETag,
			}

			// Gunakan mutex untuk melindungi data bersama.
			mu.Lock()
			parts = append(parts, part)
			mu.Unlock()
		}(i+1, start, end)
	}

	// Tunggu hingga semua goroutine selesai.
	wg.Wait()

	// Selesaikan permintaan unggah multi-bagian.
	request := &oss.CompleteMultipartUploadRequest{
		Bucket:   oss.Ptr(bucketName),
		Key:      oss.Ptr(objectName),
		UploadId: oss.Ptr(uploadId),
		CompleteMultipartUpload: &oss.CompleteMultipartUpload{
			Parts: parts,
		},
	}
	result, err := client.CompleteMultipartUpload(context.TODO(), request)
	if err != nil {
		log.Fatalf("gagal menyelesaikan unggah multi-bagian %v", err)
	}

	// Cetak hasil penyelesaian unggah multi-bagian.
	log.Printf("hasil penyelesaian unggah multi-bagian:%#v\n", result)
}

Skenario umum

Unggah string acak dengan panjang tertentu menggunakan unggah multi-bagian

Kode contoh berikut menunjukkan cara membagi string acak 400 KB menjadi tiga bagian, mengunggah bagian-bagian tersebut ke bucket secara bersamaan, lalu menggabungkan bagian-bagian tersebut menjadi satu objek lengkap.

package main

import (
	"bufio"
	"context"
	"flag"
	"io"
	"log"
	"math/rand"
	"strings"
	"sync"
	"time"

	"github.com/aliyun/alibabacloud-oss-go-sdk-v2/oss"
	"github.com/aliyun/alibabacloud-oss-go-sdk-v2/oss/credentials"
)

// Tentukan variabel global.
var (
	region     string                                                                     // Wilayah.
	bucketName string                                                                     // Nama bucket.
	objectName string                                                                     // Nama objek.
	letters    = []rune("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ") // Set karakter yang digunakan untuk menghasilkan string acak.
)

// Fungsi init digunakan untuk menginisialisasi parameter baris perintah.
func init() {
	flag.StringVar(&region, "region", "", "Wilayah tempat bucket berada.")
	flag.StringVar(&bucketName, "bucket", "", "Nama bucket.")
	flag.StringVar(&objectName, "object", "", "Nama objek.")
}

func main() {
	// Parsing parameter baris perintah.
	flag.Parse()

	// Tentukan ID unggah.
	var uploadId string

	// Periksa apakah nama bucket kosong.
	if len(bucketName) == 0 {
		flag.PrintDefaults()
		log.Fatalf("parameter tidak valid, nama bucket diperlukan")
	}

	// Periksa apakah wilayah kosong.
	if len(region) == 0 {
		flag.PrintDefaults()
		log.Fatalf("parameter tidak valid, wilayah diperlukan")
	}

	// Periksa apakah nama objek kosong.
	if len(objectName) == 0 {
		flag.PrintDefaults()
		log.Fatalf("parameter tidak valid, nama objek diperlukan")
	}

	// Muat konfigurasi default, dan atur penyedia kredensial dan wilayah.
	cfg := oss.LoadDefaultConfig().
		WithCredentialsProvider(credentials.NewEnvironmentVariableCredentialsProvider()).
		WithRegion(region)

	// Buat klien OSS.
	client := oss.NewClient(cfg)

	// Buat permintaan untuk memulai unggah multi-bagian.
	initRequest := &oss.InitiateMultipartUploadRequest{
		Bucket: oss.Ptr(bucketName), // Nama bucket.
		Key:    oss.Ptr(objectName), // Nama objek.
	}

	// Mulai unggah multi-bagian dan proses hasilnya.
	initResult, err := client.InitiateMultipartUpload(context.TODO(), initRequest)
	if err != nil {
		log.Fatalf("gagal memulai unggah multi-bagian %v", err)
	}

	// Cetak hasil memulai unggah multi-bagian.
	log.Printf("hasil inisiasi unggah multi-bagian:%#v\n", initResult)
	uploadId = *initResult.UploadId

	// Inisialisasi wait group dan mutex.
	var wg sync.WaitGroup
	var parts []oss.UploadPart
	count := 3
	body := randBody(400000) // Hasilkan string acak 400 KB.
	reader := strings.NewReader(body)
	bufReader := bufio.NewReader(reader)
	content, _ := io.ReadAll(bufReader)
	partSize := len(body) / count
	var mu sync.Mutex

	// Mulai beberapa goroutine untuk mengunggah bagian.
	for i := 0; i < count; i++ {
		wg.Add(1)
		go func(partNumber int, partSize int, i int) {
			defer wg.Done()

			// Buat permintaan untuk mengunggah bagian.
			partRequest := &oss.UploadPartRequest{
				Bucket:     oss.Ptr(bucketName),                                             // Nama bucket.
				Key:        oss.Ptr(objectName),                                             // Nama objek.
				PartNumber: int32(partNumber),                                               // Nomor bagian.
				UploadId:   oss.Ptr(uploadId),                                               // ID unggah.
				Body:       strings.NewReader(string(content[i*partSize : (i+1)*partSize])), // Konten bagian.
			}

			// Kirim permintaan untuk mengunggah bagian.
			partResult, err := client.UploadPart(context.TODO(), partRequest)
			if err != nil {
				log.Fatalf("gagal mengunggah bagian %d: %v", partNumber, err)
			}

			// Catat hasil unggah bagian.
			part := oss.UploadPart{
				PartNumber: partRequest.PartNumber,
				ETag:       partResult.ETag,
			}

			// Gunakan mutex untuk melindungi data bersama.
			mu.Lock()
			parts = append(parts, part)
			mu.Unlock()
		}(i+1, partSize, i)
	}

	// Tunggu hingga semua goroutine selesai.
	wg.Wait()

	// Cetak pesan yang menunjukkan bahwa unggah bagian berhasil.
	log.Println("unggah bagian berhasil!")

	// Buat permintaan untuk menyelesaikan unggah multi-bagian.
	request := &oss.CompleteMultipartUploadRequest{
		Bucket:   oss.Ptr(bucketName),
		Key:      oss.Ptr(objectName),
		UploadId: oss.Ptr(uploadId),
		CompleteMultipartUpload: &oss.CompleteMultipartUpload{
			Parts: parts,
		},
	}

	// Selesaikan unggah multi-bagian dan proses hasilnya.
	result, err := client.CompleteMultipartUpload(context.TODO(), request)
	if err != nil {
		log.Fatalf("gagal menyelesaikan unggah multi-bagian %v", err)
	}
	log.Printf("hasil penyelesaian unggah multi-bagian:%#v\n", result)
}

// randBody menghasilkan string acak dengan panjang tertentu.
func randBody(n int) string {
	b := make([]rune, n)
	randMarker := rand.New(rand.NewSource(time.Now().UnixNano()))
	for i := range b {
		b[i] = letters[randMarker.Intn(len(letters))]
	}
	return string(b)
}

Batalkan peristiwa unggah multi-bagian yang ditentukan

Anda dapat menggunakan metode Client.AbortMultipartUpload untuk membatalkan unggah multi-bagian dalam skenario berikut.

  1. Kesalahan File:

    • Jika Anda menemukan kesalahan pada file selama pengunggahan, seperti kerusakan file atau kode jahat, Anda dapat membatalkan pengunggahan untuk menghindari ancaman potensial.

  2. Jaringan Tidak Stabil:

    • Saat konektivitas jaringan tidak stabil atau terputus, bagian-bagian mungkin hilang atau rusak selama proses pengunggahan. Anda dapat membatalkan pengunggahan dan memulainya kembali untuk memastikan integritas dan konsistensi data.

  3. Batas Sumber Daya:

    • Jika bucket Anda memiliki ruang penyimpanan terbatas dan file yang akan diunggah terlalu besar, Anda dapat membatalkan pengunggahan untuk melepaskan ruang penyimpanan dan mengalokasikan sumber daya untuk tugas yang lebih penting.

  4. Operasi Tidak Disengaja:

    • Jika Anda secara tidak sengaja memulai tugas pengunggahan yang tidak perlu atau mengunggah versi file yang salah, Anda dapat membatalkan peristiwa pengunggahan ini.

package main

import (
	"context"
	"flag"
	"log"

	"github.com/aliyun/alibabacloud-oss-go-sdk-v2/oss"
	"github.com/aliyun/alibabacloud-oss-go-sdk-v2/oss/credentials"
)

// Tentukan variabel global.
var (
	region     string // Wilayah.
	bucketName string // Nama bucket sumber.
	objectName string // Nama objek sumber.

)

// Fungsi init digunakan untuk menginisialisasi parameter baris perintah.
func init() {
	flag.StringVar(&region, "region", "", "Wilayah tempat bucket berada.")
	flag.StringVar(&bucketName, "bucket", "", "Nama bucket sumber.")
	flag.StringVar(&objectName, "object", "", "Nama objek sumber.")
}

func main() {
	// Parsing parameter baris perintah.
	flag.Parse()

	// Tentukan ID unggah.
	var uploadId string

	// Periksa apakah nama bucket sumber kosong.
	if len(bucketName) == 0 {
		flag.PrintDefaults()
		log.Fatalf("parameter tidak valid, nama bucket sumber diperlukan")
	}

	// Periksa apakah wilayah kosong.
	if len(region) == 0 {
		flag.PrintDefaults()
		log.Fatalf("parameter tidak valid, wilayah diperlukan")
	}

	// Periksa apakah nama objek sumber kosong.
	if len(objectName) == 0 {
		flag.PrintDefaults()
		log.Fatalf("parameter tidak valid, nama objek sumber diperlukan")
	}

	// Muat konfigurasi default, dan atur penyedia kredensial dan wilayah.
	cfg := oss.LoadDefaultConfig().
		WithCredentialsProvider(credentials.NewEnvironmentVariableCredentialsProvider()).
		WithRegion(region)

	// Buat klien OSS.
	client := oss.NewClient(cfg)

	// Mulai permintaan unggah multi-bagian.
	initRequest := &oss.InitiateMultipartUploadRequest{
		Bucket: oss.Ptr(bucketName),
		Key:    oss.Ptr(objectName),
	}

	// Eksekusi permintaan untuk memulai unggah multi-bagian.
	initResult, err := client.InitiateMultipartUpload(context.TODO(), initRequest)
	if err != nil {
		log.Fatalf("gagal memulai unggah multi-bagian %v", err)
	}

	// Cetak hasil memulai unggah multi-bagian.
	log.Printf("hasil inisiasi unggah multi-bagian:%#v\n", *initResult.UploadId)
	uploadId = *initResult.UploadId

	// Buat permintaan AbortMultipartUploadRequest.
	request := &oss.AbortMultipartUploadRequest{
		Bucket:   oss.Ptr(bucketName), // Nama bucket.
		Key:      oss.Ptr(objectName), // Nama objek.
		UploadId: oss.Ptr(uploadId),   // ID unggah.
	}
	// Eksekusi permintaan dan proses hasilnya.
	result, err := client.AbortMultipartUpload(context.TODO(), request)
	if err != nil {
		log.Fatalf("gagal membatalkan unggah multi-bagian %v", err)
	}
	log.Printf("hasil pembatalan unggah multi-bagian:%#v\n", result)

}

Daftar bagian yang telah berhasil diunggah dalam peristiwa unggah multi-bagian yang ditentukan

Anda dapat menggunakan paginator Client.NewListPartsPaginator untuk mencantumkan bagian-bagian yang berhasil diunggah dalam skenario unggah multi-bagian.

Monitor Kemajuan Unggah:

  1. Pengunggahan File Besar:

    • Saat Anda mengunggah file yang sangat besar, Anda dapat mencantumkan bagian-bagian yang telah diunggah untuk memastikan bahwa proses unggah berjalan sesuai harapan dan mendeteksi masalah secara tepat waktu.

  2. Pengunggahan yang Dapat Dilanjutkan:

    • Jika jaringan tidak stabil atau pengunggahan terganggu, Anda dapat melihat bagian-bagian yang telah diunggah untuk menentukan apakah perlu mencoba lagi mengunggah bagian-bagian yang belum selesai. Ini memungkinkan Anda mengimplementasikan pengunggahan yang dapat dilanjutkan.

  3. Pemecahan Masalah:

    • Jika terjadi kesalahan selama pengunggahan, Anda dapat memeriksa bagian-bagian yang telah diunggah untuk dengan cepat menemukan masalah. Misalnya, bagian tertentu gagal diunggah. Kemudian, Anda dapat menyelesaikan masalah tersebut secara terarah.

  4. Manajemen Sumber Daya:

    • Untuk skenario yang memerlukan kontrol ketat atas penggunaan sumber daya, Anda dapat memantau kemajuan pengunggahan untuk mengelola ruang penyimpanan dan sumber daya bandwidth dengan lebih baik serta memastikan pemanfaatan sumber daya yang efisien.

package main

import (
	"context"
	"flag"
	"log"

	"github.com/aliyun/alibabacloud-oss-go-sdk-v2/oss"
	"github.com/aliyun/alibabacloud-oss-go-sdk-v2/oss/credentials"
)

// Tentukan variabel global.
var (
	region     string // Wilayah.
	bucketName string // Nama bucket sumber.
	objectName string // Nama objek sumber.

)

// Fungsi init digunakan untuk menginisialisasi parameter baris perintah.
func init() {
	flag.StringVar(&region, "region", "", "Wilayah tempat bucket berada.")
	flag.StringVar(&bucketName, "bucket", "", "Nama bucket sumber.")
	flag.StringVar(&objectName, "object", "", "Nama objek sumber.")
}

func main() {
	// Parsing parameter baris perintah.
	flag.Parse()

	// Tentukan ID unggah.
	var uploadId string

	// Periksa apakah nama bucket sumber kosong.
	if len(bucketName) == 0 {
		flag.PrintDefaults()
		log.Fatalf("parameter tidak valid, nama bucket sumber diperlukan")
	}

	// Periksa apakah wilayah kosong.
	if len(region) == 0 {
		flag.PrintDefaults()
		log.Fatalf("parameter tidak valid, wilayah diperlukan")
	}

	// Periksa apakah nama objek sumber kosong.
	if len(objectName) == 0 {
		flag.PrintDefaults()
		log.Fatalf("parameter tidak valid, nama objek sumber diperlukan")
	}

	// Muat konfigurasi default, dan atur penyedia kredensial dan wilayah.
	cfg := oss.LoadDefaultConfig().
		WithCredentialsProvider(credentials.NewEnvironmentVariableCredentialsProvider()).
		WithRegion(region)

	// Buat klien OSS.
	client := oss.NewClient(cfg)

	// Mulai permintaan unggah multi-bagian.
	initRequest := &oss.InitiateMultipartUploadRequest{
		Bucket: oss.Ptr(bucketName),
		Key:    oss.Ptr(objectName),
	}

	// Eksekusi permintaan untuk memulai unggah multi-bagian.
	initResult, err := client.InitiateMultipartUpload(context.TODO(), initRequest)
	if err != nil {
		log.Fatalf("gagal memulai unggah multi-bagian %v", err)
	}

	// Cetak hasil memulai unggah multi-bagian.
	log.Printf("hasil inisiasi unggah multi-bagian:%#v\n", *initResult.UploadId)
	uploadId = *initResult.UploadId

	// Buat permintaan untuk mencantumkan bagian.
	request := &oss.ListPartsRequest{
		Bucket:   oss.Ptr(bucketName), // Nama bucket.
		Key:      oss.Ptr(objectName), // Nama objek.
		UploadId: oss.Ptr(uploadId),   // ID unggah.
	}

	// Buat paginator.
	p := client.NewListPartsPaginator(request)

	// Inisialisasi penghitung nomor halaman.
	var i int
	log.Println("Daftar Bagian:")

	// Telusuri setiap halaman dalam paginator.
	for p.HasNext() {
		i++

		// Dapatkan data pada halaman berikutnya.
		page, err := p.NextPage(context.TODO())
		if err != nil {
			log.Fatalf("gagal mendapatkan halaman %v, %v", i, err)
		}

		// Cetak informasi tentang setiap bagian pada halaman.
		for _, part := range page.Parts {
			log.Printf("Nomor Bagian: %v, ETag: %v, Terakhir Dimodifikasi: %v, Ukuran: %v, HashCRC64: %v\n",
				part.PartNumber,
				oss.ToString(part.ETag),
				oss.ToTime(part.LastModified),
				part.Size,
				oss.ToString(part.HashCRC64))
		}
	}

}

Daftar peristiwa unggah multi-bagian

Anda dapat menggunakan paginator Client.NewListMultipartUploadsPaginator untuk mencantumkan semua unggah multi-bagian yang sedang berlangsung dalam bucket pada skenario berikut.

Skema Pemantauan:

  1. Manajemen Pengunggahan File Batch:

    • Ketika Anda perlu mengunggah banyak file, Anda dapat menggunakan metode ListMultipartUploads untuk memantau semua aktivitas unggah multi-bagian secara real-time, sehingga memastikan bahwa semua file diunggah dengan benar.

  2. Deteksi Kesalahan dan Pemulihan:

    • Jika masalah jaringan atau kesalahan lain terjadi selama proses pengunggahan, beberapa bagian mungkin gagal diunggah. Dengan memantau peristiwa unggah multi-bagian yang sedang berlangsung, Anda dapat mendeteksi masalah ini secara tepat waktu dan mengambil tindakan untuk melanjutkan pengunggahan.

  3. Optimalisasi dan Manajemen Sumber Daya:

    • Selama pengunggahan file skala besar, memantau peristiwa unggah multi-bagian yang sedang berlangsung dapat membantu mengoptimalkan alokasi sumber daya, seperti menyesuaikan penggunaan bandwidth atau mengoptimalkan kebijakan pengunggahan berdasarkan kemajuan pengunggahan.

  4. Migrasi Data:

    • Saat Anda melakukan proyek migrasi data skala besar, Anda dapat memantau semua peristiwa unggah multi-bagian yang sedang berlangsung untuk memastikan kelancaran tugas migrasi dan mendeteksi serta menyelesaikan masalah potensial secara tepat waktu.

Pengaturan parameter

Parameter

Deskripsi

Delimiter

Karakter yang digunakan untuk mengelompokkan nama objek. Semua objek yang namanya mengandung awalan yang ditentukan dan berada di antara kemunculan pertama karakter Delimiter diperlakukan sebagai satu grup elemen.

MaxUploads

Jumlah maksimum peristiwa unggah multi-bagian yang akan dikembalikan. Nilai default dan nilai maksimumnya adalah 1000.

KeyMarker

Peristiwa unggah multi-bagian file yang namanya secara leksikografis lebih besar dari nilai KeyMarker. Anda dapat menggunakan parameter ini dengan parameter UploadIDMarker untuk menentukan posisi awal hasil yang dikembalikan.

Prefix

Awalan yang harus dimiliki oleh nama file yang dikembalikan. Perhatikan bahwa jika Anda menggunakan parameter Prefix dalam kueri, nama file yang dikembalikan mencakup awalan tersebut.

UploadIDMarker

Digunakan bersama dengan parameter KeyMarker untuk menentukan posisi awal hasil yang dikembalikan.

  • Jika parameter KeyMarker tidak diatur, OSS mengabaikan parameter ini.

  • Jika parameter KeyMarker diatur, hasil kueri mencakup hal berikut:

    • Peristiwa unggah multi-bagian semua objek yang namanya secara leksikografis lebih besar dari nilai parameter KeyMarker.

    • Peristiwa unggah multi-bagian objek yang namanya sama dengan nilai parameter KeyMarker tetapi ID unggahnya lebih besar dari nilai parameter UploadIDMarker.

  • Tentukan bahwa awalan adalah file dan maksimum 100 hasil dikembalikan.

    package main
    
    import (
    	"context"
    	"flag"
    	"log"
    
    	"github.com/aliyun/alibabacloud-oss-go-sdk-v2/oss"
    	"github.com/aliyun/alibabacloud-oss-go-sdk-v2/oss/credentials"
    )
    
    // Tentukan variabel global.
    var (
    	region     string // Wilayah.
    	bucketName string // Nama bucket sumber.
    	objectName string // Nama objek sumber.
    
    )
    
    // Fungsi init digunakan untuk menginisialisasi parameter baris perintah.
    func init() {
    	flag.StringVar(&region, "region", "", "Wilayah tempat bucket berada.")
    	flag.StringVar(&bucketName, "bucket", "", "Nama bucket sumber.")
    	flag.StringVar(&objectName, "object", "", "Nama objek sumber.")
    }
    
    func main() {
    	// Parsing parameter baris perintah.
    	flag.Parse()
    
    	// Periksa apakah nama bucket sumber kosong.
    	if len(bucketName) == 0 {
    		flag.PrintDefaults()
    		log.Fatalf("parameter tidak valid, nama bucket sumber diperlukan")
    	}
    
    	// Periksa apakah wilayah kosong.
    	if len(region) == 0 {
    		flag.PrintDefaults()
    		log.Fatalf("parameter tidak valid, wilayah diperlukan")
    	}
    
    	// Periksa apakah nama objek sumber kosong.
    	if len(objectName) == 0 {
    		flag.PrintDefaults()
    		log.Fatalf("parameter tidak valid, nama objek sumber diperlukan")
    	}
    
    	// Muat konfigurasi default, dan atur penyedia kredensial dan wilayah.
    	cfg := oss.LoadDefaultConfig().
    		WithCredentialsProvider(credentials.NewEnvironmentVariableCredentialsProvider()).
    		WithRegion(region)
    
    	// Buat klien OSS.
    	client := oss.NewClient(cfg)
    
    	// Buat permintaan untuk mencantumkan unggah multi-bagian.
    	request := &oss.ListMultipartUploadsRequest{
    		Bucket:     oss.Ptr(bucketName), // Nama bucket.
    		MaxUploads: 100,                 // Tentukan bahwa maksimum 100 hasil dikembalikan.
    		Prefix:     oss.Ptr("file"),     // Tentukan bahwa awalan adalah file.
    	}
    
    	// Buat paginator.
    	p := client.NewListMultipartUploadsPaginator(request)
    
    	var i int
    	log.Println("Daftar Unggah Multi-Bagian:")
    
    	// Telusuri setiap halaman dalam paginator.
    	for p.HasNext() {
    		i++
    
    		// Dapatkan data pada halaman berikutnya.
    		page, err := p.NextPage(context.TODO())
    		if err != nil {
    			log.Fatalf("gagal mendapatkan halaman %v, %v", i, err)
    		}
    
    		// Cetak informasi tentang setiap unggah multi-bagian pada halaman.
    		for _, u := range page.Uploads {
    			log.Printf("Kunci unggah: %v, ID unggah: %v, dimulai: %v\n", oss.ToString(u.Key), oss.ToString(u.UploadId), oss.ToTime(u.Initiated))
    		}
    	}
    
    }
    

Unggah multi-bagian dengan callback

Kode berikut menunjukkan cara membagi file 400 KB menjadi tiga bagian dan mengunggahnya secara bersamaan ke Alibaba Cloud OSS. Setelah bagian-bagian digabungkan menjadi satu objek lengkap, notifikasi callback dipicu.

package main

import (
	"bufio"
	"context"
	"encoding/base64"
	"encoding/json"
	"flag"
	"io"
	"log"
	"math/rand"
	"strings"
	"sync"
	"time"

	"github.com/aliyun/alibabacloud-oss-go-sdk-v2/oss"
	"github.com/aliyun/alibabacloud-oss-go-sdk-v2/oss/credentials"
)

var (
	region     string
	bucketName string
	objectName string
	letters    = []rune("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
)

func init() {
	flag.StringVar(&region, "region", "", "Wilayah tempat bucket berada.")
	flag.StringVar(&bucketName, "bucket", "", "Nama bucket.")
	flag.StringVar(&objectName, "object", "", "Nama objek.")
}

func main() {
	flag.Parse()
	if len(bucketName) == 0 {
		flag.PrintDefaults()
		log.Fatalf("parameter tidak valid, nama bucket diperlukan")
	}

	if len(region) == 0 {
		flag.PrintDefaults()
		log.Fatalf("parameter tidak valid, wilayah diperlukan")
	}

	if len(objectName) == 0 {
		flag.PrintDefaults()
		log.Fatalf("parameter tidak valid, nama objek diperlukan")
	}

	cfg := oss.LoadDefaultConfig().
		WithCredentialsProvider(credentials.NewEnvironmentVariableCredentialsProvider()).
		WithRegion(region)

	client := oss.NewClient(cfg)

	initRequest := &oss.InitiateMultipartUploadRequest{
		Bucket: oss.Ptr(bucketName),
		Key:    oss.Ptr(objectName),
	}
	initResult, err := client.InitiateMultipartUpload(context.TODO(), initRequest)

	// Tentukan parameter callback.
	callbackMap := map[string]string{
		"callbackUrl":      "https://example.com:23450",                                                                  // Atur URL server callback. Contoh: https://example.com:23450.
		"callbackBody":     "bucket=${bucket}&object=${object}&size=${size}&my_var_1=${x:my_var1}&my_var_2=${x:my_var2}", // Atur body permintaan untuk callback.
		"callbackBodyType": "application/x-www-form-urlencoded",                                                          // Atur tipe body permintaan untuk callback.
	}

	// Konversi parameter callback ke JSON lalu lakukan encoding Base64 agar parameter dapat dilewatkan sebagai parameter callback.
	callbackStr, err := json.Marshal(callbackMap)
	if err != nil {
		log.Fatalf("gagal melakukan marshal callback map: %v", err)
	}
	callbackBase64 := base64.StdEncoding.EncodeToString(callbackStr)

	callbackVarMap := map[string]string{}
	callbackVarMap["x:my_var1"] = "ini adalah var 1"
	callbackVarMap["x:my_var2"] = "ini adalah var 2"
	callbackVarStr, err := json.Marshal(callbackVarMap)
	if err != nil {
		log.Fatalf("gagal melakukan marshal callback var: %v", err)
	}
	callbackVarBase64 := base64.StdEncoding.EncodeToString(callbackVarStr)

	var wg sync.WaitGroup
	var parts []oss.UploadPart
	count := 3
	body := randBody(400000)
	reader := strings.NewReader(body)
	bufReader := bufio.NewReader(reader)
	content, _ := io.ReadAll(bufReader)
	partSize := len(body) / count
	var mu sync.Mutex
	for i := 0; i < count; i++ {
		wg.Add(1)
		go func(partNumber int, partSize int, i int) {
			defer wg.Done()
			partRequest := &oss.UploadPartRequest{
				Bucket:     oss.Ptr(bucketName),
				Key:        oss.Ptr(objectName),
				PartNumber: int32(partNumber),
				UploadId:   initResult.UploadId,
				Body:       strings.NewReader(string(content[i*partSize : (i+1)*partSize])),
			}
			partResult, err := client.UploadPart(context.TODO(), partRequest)
			if err != nil {
				log.Fatalf("gagal mengunggah bagian %d: %v", partNumber, err)
			}
			part := oss.UploadPart{
				PartNumber: partRequest.PartNumber,
				ETag:       partResult.ETag,
			}
			mu.Lock()
			parts = append(parts, part)
			mu.Unlock()
		}(i+1, partSize, i)
	}
	wg.Wait()

	request := &oss.CompleteMultipartUploadRequest{
		Bucket:   oss.Ptr(bucketName),
		Key:      oss.Ptr(objectName),
		UploadId: initResult.UploadId,
		CompleteMultipartUpload: &oss.CompleteMultipartUpload{
			Parts: parts,
		},
		Callback:    oss.Ptr(callbackBase64), // Tentukan parameter callback.
		CallbackVar: oss.Ptr(callbackVarBase64),
	}
	result, err := client.CompleteMultipartUpload(context.TODO(), request)
	if err != nil {
		log.Fatalf("gagal menyelesaikan unggah multi-bagian %v", err)
	}
	log.Printf("hasil penyelesaian unggah multi-bagian:%#v\n", result)
}

func randBody(n int) string {
	b := make([]rune, n)
	randMarker := rand.New(rand.NewSource(time.Now().UnixNano()))
	for i := range b {
		b[i] = letters[randMarker.Intn(len(letters))]
	}
	return string(b)
}

Unggah multi-bagian dengan progress bar

package main

import (
	"bufio"
	"bytes"
	"context"
	"flag"
	"fmt"
	"io"
	"log"
	"os"
	"sync"

	"github.com/aliyun/alibabacloud-oss-go-sdk-v2/oss"
	"github.com/aliyun/alibabacloud-oss-go-sdk-v2/oss/credentials"
)

// Tentukan variabel global.
var (
	region     string // Wilayah.
	bucketName string // Nama bucket sumber.
	objectName string // Nama objek sumber.

)

// Fungsi init digunakan untuk menginisialisasi parameter baris perintah.
func init() {
	flag.StringVar(&region, "region", "", "Wilayah tempat bucket berada.")
	flag.StringVar(&bucketName, "bucket", "", "Nama bucket sumber.")
	flag.StringVar(&objectName, "object", "", "Nama objek sumber.")
}

func main() {
	// Parsing parameter baris perintah.
	flag.Parse()

	// Tentukan ID unggah.
	var uploadId string

	// Periksa apakah nama bucket sumber kosong.
	if len(bucketName) == 0 {
		flag.PrintDefaults()
		log.Fatalf("parameter tidak valid, nama bucket sumber diperlukan")
	}

	// Periksa apakah wilayah kosong.
	if len(region) == 0 {
		flag.PrintDefaults()
		log.Fatalf("parameter tidak valid, wilayah diperlukan")
	}

	// Periksa apakah nama objek sumber kosong.
	if len(objectName) == 0 {
		flag.PrintDefaults()
		log.Fatalf("parameter tidak valid, nama objek sumber diperlukan")
	}

	// Muat konfigurasi default, dan atur penyedia kredensial dan wilayah.
	cfg := oss.LoadDefaultConfig().
		WithCredentialsProvider(credentials.NewEnvironmentVariableCredentialsProvider()).
		WithRegion(region)

	// Buat klien OSS.
	client := oss.NewClient(cfg)

	// Mulai permintaan unggah multi-bagian.
	initRequest := &oss.InitiateMultipartUploadRequest{
		Bucket:  oss.Ptr(bucketName),
		Key:     oss.Ptr(objectName),
	}

	// Eksekusi permintaan untuk memulai unggah multi-bagian.
	initResult, err := client.InitiateMultipartUpload(context.TODO(), initRequest)
	if err != nil {
		log.Fatalf("gagal memulai unggah multi-bagian %v", err)
	}

	// Cetak hasil memulai unggah multi-bagian.
	log.Printf("hasil inisiasi unggah multi-bagian:%#v\n", *initResult.UploadId)
	uploadId = *initResult.UploadId

	// Inisialisasi wait group dan mutex.
	var wg sync.WaitGroup
	var parts []oss.UploadPart
	count := 5
	var mu sync.Mutex

	// Baca konten file lokal ke dalam memori. Ganti /Users/yourLocalPath/yourFileName dengan nama dan jalur file lokal sebenarnya.
	file, err := os.Open("/Users/yourLocalPath/yourFileName")
	if err != nil {
		log.Fatalf("gagal membuka file lokal %v", err)
	}
	defer file.Close()

	bufReader := bufio.NewReader(file)
	content, err := io.ReadAll(bufReader)
	if err != nil {
		log.Fatalf("gagal membaca file lokal %v", err)
	}
	log.Printf("ukuran file: %d\n", len(content))

	// Hitung ukuran setiap bagian.
	chunkSize := len(content) / count
	if chunkSize == 0 {
		chunkSize = 1
	}

	// Mulai beberapa goroutine untuk mengunggah bagian.
	for i := 0; i < count; i++ {
		start := i * chunkSize
		end := start + chunkSize
		if i == count-1 {
			end = len(content)
		}

		wg.Add(1)
		go func(partNumber int, start, end int) {
			defer wg.Done()

			// Buat permintaan untuk mengunggah bagian.
			partRequest := &oss.UploadPartRequest{
				Bucket:     oss.Ptr(bucketName),                 // Nama bucket tujuan.
				Key:        oss.Ptr(objectName),                 // Nama objek tujuan.
				PartNumber: int32(partNumber),                   // Nomor bagian.
				UploadId:   oss.Ptr(uploadId),                   // ID unggah.
				Body:       bytes.NewReader(content[start:end]), // Konten bagian.
				ProgressFn: func(increment, transferred, total int64) {
					fmt.Printf("increment:%v, transferred:%v, total:%v\n", increment, transferred, total)
				}, // Fungsi callback kemajuan, yang digunakan untuk menampilkan kemajuan pengunggahan.
			}

			// Kirim permintaan untuk mengunggah bagian.
			partResult, err := client.UploadPart(context.TODO(), partRequest)
			if err != nil {
				log.Fatalf("gagal mengunggah bagian %d: %v", partNumber, err)
			}

			log.Printf("berhasil mengunggah bagian %d (mulai: %d, akhir: %d)", partNumber, start, end)

			// Catat hasil unggah bagian.
			part := oss.UploadPart{
				PartNumber: partRequest.PartNumber,
				ETag:       partResult.ETag,
			}

			// Gunakan mutex untuk melindungi data bersama.
			mu.Lock()
			parts = append(parts, part)
			mu.Unlock()
		}(i+1, start, end)
	}

	// Tunggu hingga semua goroutine selesai.
	wg.Wait()

	// Selesaikan permintaan unggah multi-bagian.
	request := &oss.CompleteMultipartUploadRequest{
		Bucket:   oss.Ptr(bucketName),
		Key:      oss.Ptr(objectName),
		UploadId: oss.Ptr(uploadId),
		CompleteMultipartUpload: &oss.CompleteMultipartUpload{
			Parts: parts,
		},
	}
	result, err := client.CompleteMultipartUpload(context.TODO(), request)
	if err != nil {
		log.Fatalf("gagal menyelesaikan unggah multi-bagian %v", err)
	}

	// Cetak versionId dari unggah multi-bagian yang telah selesai.
	log.Printf("hasil penyelesaian unggah multi-bagian versionId:%#v\n", result)
}

Referensi