すべてのプロダクト
Search
ドキュメントセンター

Object Storage Service:マルチパートアップロード (Go SDK V2)

最終更新日:Nov 09, 2025

Object Storage Service (OSS) は、ラージオブジェクトを複数のパートに分けてアップロードできるマルチパートアップロード機能を提供します。すべてのパートがアップロードされた後、CompleteMultipartUpload 操作を呼び出して、それらを完全なオブジェクトに結合できます。

注意事項

  • このトピックのサンプルコードでは、中国 (杭州) リージョンのリージョン ID cn-hangzhou を使用します。デフォルトでは、パブリックエンドポイントを使用してバケット内のリソースにアクセスします。同じリージョン内の他の Alibaba Cloud サービスからバケットリソースにアクセスする場合は、内部エンドポイントを使用します。OSS のリージョンとエンドポイントの詳細については、「リージョンとエンドポイント」をご参照ください。

  • このトピックでは、アクセス資格情報は環境変数から取得されます。アクセス資格情報の設定方法の詳細については、「アクセス資格情報の設定」をご参照ください。

  • マルチパートアップロードを使用するには、oss:PutObject 権限が必要です。詳細については、「RAM ユーザーへのカスタムポリシーのアタッチ」をご参照ください。

マルチパートアップロードのプロセス

マルチパートアップロードには、次の 3 つのステップが含まれます。

  1. マルチパートアップロードイベントを開始します。

    Client.InitiateMultipartUpload メソッドを呼び出して、OSS によって作成されたグローバルに一意のアップロード ID を取得します。

  2. パートをアップロードします。

    Client.UploadPart メソッドを呼び出して、パートデータをアップロードします。

    説明
    • 特定のアップロード ID に対して、パート番号は完全なオブジェクト内でのパートの位置を識別します。同じパート番号を使用して新しいデータをアップロードすると、OSS 内のパートの既存データは上書きされます。

    • OSS は、受信したパートデータの MD5 ハッシュを、ユーザーに返される ETag ヘッダーに含めます。

    • OSS は、アップロードされたデータの MD5 ハッシュを計算し、SDK によって計算された MD5 ハッシュと比較します。2 つの MD5 ハッシュが異なる場合、InvalidDigest エラーコードが返されます。

  3. マルチパートアップロードを完了します。

    すべてのパートがアップロードされた後、Client.CompleteMultipartUpload メソッドを呼び出して、パートを完全なオブジェクトに結合します。

次のサンプルコードは、大きなローカルファイルを複数のパートに分割し、それらのパートをバケットに同時にアップロードしてから、パートを完全なオブジェクトに結合する方法を示しています。

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"
)

// グローバル変数を定義します。
var (
	region     string // リージョン。
	bucketName string // ソースバケットの名前。
	objectName string // ソースオブジェクトの名前。

)

// init 関数は、コマンドラインパラメーターを初期化するために使用されます。
func init() {
	flag.StringVar(&region, "region", "", "The region in which the bucket is located.")
	flag.StringVar(&bucketName, "bucket", "", "The name of the source bucket.")
	flag.StringVar(&objectName, "object", "", "The name of the source object.")
}

func main() {
	// コマンドラインパラメーターを解析します。
	flag.Parse()

	// アップロード ID を定義します。
	var uploadId string

	// ソースバケット名が空かどうかを確認します。
	if len(bucketName) == 0 {
		flag.PrintDefaults()
		log.Fatalf("invalid parameters, source bucket name required")
	}

	// リージョンが空かどうかを確認します。
	if len(region) == 0 {
		flag.PrintDefaults()
		log.Fatalf("invalid parameters, region required")
	}

	// ソースオブジェクト名が空かどうかを確認します。
	if len(objectName) == 0 {
		flag.PrintDefaults()
		log.Fatalf("invalid parameters, source object name required")
	}

	// デフォルトの構成をロードし、資格情報プロバイダーとリージョンを設定します。
	cfg := oss.LoadDefaultConfig().
		WithCredentialsProvider(credentials.NewEnvironmentVariableCredentialsProvider()).
		WithRegion(region)

	// OSS クライアントを作成します。
	client := oss.NewClient(cfg)

	// マルチパートアップロードリクエストを開始します。
	initRequest := &oss.InitiateMultipartUploadRequest{
		Bucket: oss.Ptr(bucketName),
		Key:    oss.Ptr(objectName),
	}
	initResult, err := client.InitiateMultipartUpload(context.TODO(), initRequest)
	if err != nil {
		log.Fatalf("failed to initiate multipart upload %v", err)
	}

	// マルチパートアップロードの開始結果を出力します。
	log.Printf("initiate multipart upload result:%#v\n", *initResult.UploadId)
	uploadId = *initResult.UploadId

	// wait group と mutex を初期化します。
	var wg sync.WaitGroup
	var parts []oss.UploadPart
	count := 3
	var mu sync.Mutex

	// ローカルファイルの内容をメモリに読み込みます。yourLocalFile を実際のローカルファイル名とパスに置き換えます。
	file, err := os.Open("yourLocalFile")
	if err != nil {
		log.Fatalf("failed to open local file %v", err)
	}
	defer file.Close()

	bufReader := bufio.NewReader(file)
	content, err := io.ReadAll(bufReader)
	if err != nil {
		log.Fatalf("failed to read local file %v", err)
	}
	log.Printf("file size: %d\n", len(content))

	// 各パートのサイズを計算します。
	chunkSize := len(content) / count
	if chunkSize == 0 {
		chunkSize = 1
	}

	// 複数のゴルーチンを開始してパートをアップロードします。
	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()

			// パートをアップロードするリクエストを作成します。
			partRequest := &oss.UploadPartRequest{
				Bucket:     oss.Ptr(bucketName),                 // 宛先バケットの名前。
				Key:        oss.Ptr(objectName),                 // 宛先オブジェクトの名前。
				PartNumber: int32(partNumber),                   // パート番号。
				UploadId:   oss.Ptr(uploadId),                   // アップロード ID。
				Body:       bytes.NewReader(content[start:end]), // パートの内容。
			}

			// パートをアップロードするリクエストを送信します。
			partResult, err := client.UploadPart(context.TODO(), partRequest)
			if err != nil {
				log.Fatalf("failed to upload part %d: %v", partNumber, err)
			}

			// パートアップロードの結果を記録します。
			part := oss.UploadPart{
				PartNumber: partRequest.PartNumber,
				ETag:       partResult.ETag,
			}

			// mutex を使用して共有データを保護します。
			mu.Lock()
			parts = append(parts, part)
			mu.Unlock()
		}(i+1, start, end)
	}

	// すべてのゴルーチンが完了するまで待ちます。
	wg.Wait()

	// マルチパートアップロードリクエストを完了します。
	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("failed to complete multipart upload %v", err)
	}

	// マルチパートアップロードの完了結果を出力します。
	log.Printf("complete multipart upload result:%#v\n", result)
}

一般的なシナリオ

マルチパートアップロードを使用して指定された長さのランダムな文字列をアップロードする

次のサンプルコードは、400 KB のランダムな文字列を 3 つのパートに分割し、それらのパートをバケットに同時にアップロードしてから、パートを完全なオブジェクトに結合する方法を示しています。

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"
)

// グローバル変数を定義します。
var (
	region     string                                                                     // リージョン。
	bucketName string                                                                     // バケットの名前。
	objectName string                                                                     // オブジェクトの名前。
	letters    = []rune("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ") // ランダムな文字列を生成するために使用される文字セット。
)

// init 関数は、コマンドラインパラメーターを初期化するために使用されます。
func init() {
	flag.StringVar(&region, "region", "", "The region in which the bucket is located.")
	flag.StringVar(&bucketName, "bucket", "", "The name of the bucket.")
	flag.StringVar(&objectName, "object", "", "The name of the object.")
}

func main() {
	// コマンドラインパラメーターを解析します。
	flag.Parse()

	// アップロード ID を定義します。
	var uploadId string

	// バケット名が空かどうかを確認します。
	if len(bucketName) == 0 {
		flag.PrintDefaults()
		log.Fatalf("invalid parameters, bucket name required")
	}

	// リージョンが空かどうかを確認します。
	if len(region) == 0 {
		flag.PrintDefaults()
		log.Fatalf("invalid parameters, region required")
	}

	// オブジェクト名が空かどうかを確認します。
	if len(objectName) == 0 {
		flag.PrintDefaults()
		log.Fatalf("invalid parameters, object name required")
	}

	// デフォルトの構成をロードし、資格情報プロバイダーとリージョンを設定します。
	cfg := oss.LoadDefaultConfig().
		WithCredentialsProvider(credentials.NewEnvironmentVariableCredentialsProvider()).
		WithRegion(region)

	// OSS クライアントを作成します。
	client := oss.NewClient(cfg)

	// マルチパートアップロードを開始するリクエストを作成します。
	initRequest := &oss.InitiateMultipartUploadRequest{
		Bucket: oss.Ptr(bucketName), // バケットの名前。
		Key:    oss.Ptr(objectName), // オブジェクトの名前。
	}

	// マルチパートアップロードを開始し、結果を処理します。
	initResult, err := client.InitiateMultipartUpload(context.TODO(), initRequest)
	if err != nil {
		log.Fatalf("failed to initiate multipart upload %v", err)
	}

	// マルチパートアップロードの開始結果を出力します。
	log.Printf("initiate multipart upload result:%#v\n", initResult)
	uploadId = *initResult.UploadId

	// wait group と mutex を初期化します。
	var wg sync.WaitGroup
	var parts []oss.UploadPart
	count := 3
	body := randBody(400000) // 400 KB のランダムな文字列を生成します。
	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:   oss.Ptr(uploadId),                                               // アップロード ID。
				Body:       strings.NewReader(string(content[i*partSize : (i+1)*partSize])), // パートの内容。
			}

			// パートをアップロードするリクエストを送信します。
			partResult, err := client.UploadPart(context.TODO(), partRequest)
			if err != nil {
				log.Fatalf("failed to upload part %d: %v", partNumber, err)
			}

			// パートアップロードの結果を記録します。
			part := oss.UploadPart{
				PartNumber: partRequest.PartNumber,
				ETag:       partResult.ETag,
			}

			// mutex を使用して共有データを保護します。
			mu.Lock()
			parts = append(parts, part)
			mu.Unlock()
		}(i+1, partSize, i)
	}

	// すべてのゴルーチンが完了するまで待ちます。
	wg.Wait()

	// パートのアップロードが成功したことを示すメッセージを出力します。
	log.Println("upload part success!")

	// マルチパートアップロードを完了するリクエストを作成します。
	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("failed to complete multipart upload %v", err)
	}
	log.Printf("complete multipart upload result:%#v\n", result)
}

// randBody は、指定された長さのランダムな文字列を生成します。
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)
}

指定されたマルチパートアップロードイベントをキャンセルする

Client.AbortMultipartUpload メソッドを使用して、次のシナリオでマルチパートアップロードイベントをキャンセルできます。

  1. ファイルエラー:

    • アップロード中にファイルにエラー (データの破損や悪意のあるコードなど) が見つかった場合、アップロードをキャンセルして潜在的な脅威を回避できます。

  2. 不安定なネットワーク:

    • ネットワーク接続が不安定または中断された場合、アップロードプロセス中にパートが失われたり破損したりする可能性があります。アップロードをキャンセルして再開することで、データの整合性と一貫性を確保できます。

  3. リソース制限:

    • バケットのストレージ容量が限られており、アップロードするファイルが大きすぎる場合、アップロードをキャンセルしてストレージリソースを解放し、より重要なタスクにリソースを割り当てることができます。

  4. 偶発的な操作:

    • 誤って不要なアップロードタスクを開始したり、不正なファイルバージョンをアップロードしたりした場合、このアップロードイベントをキャンセルできます。

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"
)

// グローバル変数を定義します。
var (
	region     string // リージョン。
	bucketName string // ソースバケットの名前。
	objectName string // ソースオブジェクトの名前。

)

// init 関数は、コマンドラインパラメーターを初期化するために使用されます。
func init() {
	flag.StringVar(&region, "region", "", "The region in which the bucket is located.")
	flag.StringVar(&bucketName, "bucket", "", "The name of the source bucket.")
	flag.StringVar(&objectName, "object", "", "The name of the source object.")
}

func main() {
	// コマンドラインパラメーターを解析します。
	flag.Parse()

	// アップロード ID を定義します。
	var uploadId string

	// ソースバケット名が空かどうかを確認します。
	if len(bucketName) == 0 {
		flag.PrintDefaults()
		log.Fatalf("invalid parameters, source bucket name required")
	}

	// リージョンが空かどうかを確認します。
	if len(region) == 0 {
		flag.PrintDefaults()
		log.Fatalf("invalid parameters, region required")
	}

	// ソースオブジェクト名が空かどうかを確認します。
	if len(objectName) == 0 {
		flag.PrintDefaults()
		log.Fatalf("invalid parameters, source object name required")
	}

	// デフォルトの構成をロードし、資格情報プロバイダーとリージョンを設定します。
	cfg := oss.LoadDefaultConfig().
		WithCredentialsProvider(credentials.NewEnvironmentVariableCredentialsProvider()).
		WithRegion(region)

	// OSS クライアントを作成します。
	client := oss.NewClient(cfg)

	// マルチパートアップロードリクエストを開始します。
	initRequest := &oss.InitiateMultipartUploadRequest{
		Bucket: oss.Ptr(bucketName),
		Key:    oss.Ptr(objectName),
	}

	// マルチパートアップロードを開始するリクエストを実行します。
	initResult, err := client.InitiateMultipartUpload(context.TODO(), initRequest)
	if err != nil {
		log.Fatalf("failed to initiate multipart upload %v", err)
	}

	// マルチパートアップロードの開始結果を出力します。
	log.Printf("initiate multipart upload result:%#v\n", *initResult.UploadId)
	uploadId = *initResult.UploadId

	// AbortMultipartUploadRequest リクエストを作成します。
	request := &oss.AbortMultipartUploadRequest{
		Bucket:   oss.Ptr(bucketName), // バケットの名前。
		Key:      oss.Ptr(objectName), // オブジェクトの名前。
		UploadId: oss.Ptr(uploadId),   // uploadId。
	}
	// リクエストを実行し、結果を処理します。
	result, err := client.AbortMultipartUpload(context.TODO(), request)
	if err != nil {
		log.Fatalf("failed to abort multipart upload %v", err)
	}
	log.Printf("abort multipart upload result:%#v\n", result)

}

指定されたマルチパートアップロードイベントで正常にアップロードされたパートをリストする

Client.NewListPartsPaginator ページネーターを使用して、次のシナリオでマルチパートアップロードイベントで正常にアップロードされたパートをリストできます。

アップロードの進行状況をモニターする:

  1. ラージファイルのアップロード:

    • 非常に大きなファイルをアップロードする場合、アップロードされたパートをリストして、アップロードプロセスが期待どおりに進行することを確認し、問題をタイムリーに検出できます。

  2. 再開可能なアップロード:

    • ネットワークが不安定であるか、アップロードが中断された場合、アップロードされたパートを表示して、不完全なパートのアップロードをリトライするかどうかを判断できます。これにより、再開可能なアップロードを実装できます。

  3. トラブルシューティング:

    • アップロード中にエラーが発生した場合、アップロードされたパートを確認して、問題を迅速に特定できます。たとえば、特定のパートのアップロードに失敗した場合などです。その後、対象を絞った方法で問題を解決できます。

  4. リソース管理:

    • リソース使用量を厳密に制御する必要があるシナリオでは、アップロードの進行状況をモニターして、ストレージ容量と帯域幅リソースをより適切に管理し、効率的なリソース使用を確保できます。

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"
)

// グローバル変数を定義します。
var (
	region     string // リージョン。
	bucketName string // ソースバケットの名前。
	objectName string // ソースオブジェクトの名前。

)

// init 関数は、コマンドラインパラメーターを初期化するために使用されます。
func init() {
	flag.StringVar(&region, "region", "", "The region in which the bucket is located.")
	flag.StringVar(&bucketName, "bucket", "", "The name of the source bucket.")
	flag.StringVar(&objectName, "object", "", "The name of the source object.")
}

func main() {
	// コマンドラインパラメーターを解析します。
	flag.Parse()

	// アップロード ID を定義します。
	var uploadId string

	// ソースバケット名が空かどうかを確認します。
	if len(bucketName) == 0 {
		flag.PrintDefaults()
		log.Fatalf("invalid parameters, source bucket name required")
	}

	// リージョンが空かどうかを確認します。
	if len(region) == 0 {
		flag.PrintDefaults()
		log.Fatalf("invalid parameters, region required")
	}

	// ソースオブジェクト名が空かどうかを確認します。
	if len(objectName) == 0 {
		flag.PrintDefaults()
		log.Fatalf("invalid parameters, source object name required")
	}

	// デフォルトの構成をロードし、資格情報プロバイダーとリージョンを設定します。
	cfg := oss.LoadDefaultConfig().
		WithCredentialsProvider(credentials.NewEnvironmentVariableCredentialsProvider()).
		WithRegion(region)

	// OSS クライアントを作成します。
	client := oss.NewClient(cfg)

	// マルチパートアップロードリクエストを開始します。
	initRequest := &oss.InitiateMultipartUploadRequest{
		Bucket: oss.Ptr(bucketName),
		Key:    oss.Ptr(objectName),
	}

	// マルチパートアップロードを開始するリクエストを実行します。
	initResult, err := client.InitiateMultipartUpload(context.TODO(), initRequest)
	if err != nil {
		log.Fatalf("failed to initiate multipart upload %v", err)
	}

	// マルチパートアップロードの開始結果を出力します。
	log.Printf("initiate multipart upload result:%#v\n", *initResult.UploadId)
	uploadId = *initResult.UploadId

	// パートをリストするリクエストを作成します。
	request := &oss.ListPartsRequest{
		Bucket:   oss.Ptr(bucketName), // バケットの名前。
		Key:      oss.Ptr(objectName), // オブジェクトの名前。
		UploadId: oss.Ptr(uploadId),   // uploadId。
	}

	// ページネーターを作成します。
	p := client.NewListPartsPaginator(request)

	// ページ番号カウンターを初期化します。
	var i int
	log.Println("List Parts:")

	// ページネーターの各ページを走査します。
	for p.HasNext() {
		i++

		// 次のページのデータを取得します。
		page, err := p.NextPage(context.TODO())
		if err != nil {
			log.Fatalf("failed to get page %v, %v", i, err)
		}

		// ページの各パートに関する情報を出力します。
		for _, part := range page.Parts {
			log.Printf("Part Number: %v, ETag: %v, Last Modified: %v, Size: %v, HashCRC64: %v\n",
				part.PartNumber,
				oss.ToString(part.ETag),
				oss.ToTime(part.LastModified),
				part.Size,
				oss.ToString(part.HashCRC64))
		}
	}

}

マルチパートアップロードイベントをリストする

Client.NewListMultipartUploadsPaginator ページネーターを使用して、次のシナリオでバケット内のすべての進行中のマルチパートアップロードイベントをリストできます。

モニタリングシナリオ:

  1. バッチファイルアップロード管理:

    • 多くのファイルをアップロードする必要がある場合、ListMultipartUploads メソッドを使用して、すべてのマルチパートアップロードアクティビティをリアルタイムでモニターし、すべてのファイルが正しくアップロードされることを確認できます。

  2. 障害検出と回復:

    • アップロードプロセス中にネットワークの問題やその他の障害が発生した場合、一部のパートのアップロードに失敗することがあります。進行中のマルチパートアップロードイベントをモニターすることで、これらの問題をタイムリーに検出し、アップロードを再開するための措置を講じることができます。

  3. リソースの最適化と管理:

    • 大規模なファイルアップロード中に、進行中のマルチパートアップロードイベントをモニターすることで、帯域幅の使用量を調整したり、アップロードの進行状況に基づいてアップロードポリシーを最適化したりするなど、リソース割り当ての最適化に役立ちます。

  4. データ移行:

    • 大規模なデータ移行プロジェクトを実行する場合、すべての進行中のマルチパートアップロードイベントをモニターして、移行タスクがスムーズに進行することを確認し、潜在的な問題をタイムリーに検出して解決できます。

パラメーター設定

パラメータ

説明

Delimiter

オブジェクト名をグループ化するために使用される文字。指定されたプレフィックスを含み、Delimiter 文字が最初に現れるまでの間にあるすべてのオブジェクトは、要素のグループとして扱われます。

MaxUploads

返すマルチパートアップロードイベントの最大数。デフォルト値と最大値はどちらも 1000 です。

KeyMarker

ファイル名が KeyMarker の値よりも辞書順で大きいファイルのマルチパートアップロードイベント。このパラメーターを UploadIDMarker パラメーターと共に使用して、返される結果の開始位置を指定できます。

Prefix

返されるファイル名に含める必要があるプレフィックス。クエリで Prefix パラメーターを使用する場合、返されるファイル名にはプレフィックスが含まれることに注意してください。

UploadIDMarker

KeyMarker パラメーターと共に使用して、返される結果の開始位置を指定します。

  • KeyMarker パラメーターが設定されていない場合、OSS はこのパラメーターを無視します。

  • KeyMarker パラメーターが設定されている場合、クエリ結果には次のものが含まれます:

    • 名前が KeyMarker パラメーターの値よりも辞書順で大きいすべてのオブジェクトのマルチパートアップロードイベント。

    • 名前が KeyMarker パラメーターの値と同じであるが、アップロード ID が UploadIDMarker パラメーターの値よりも大きいオブジェクトのマルチパートアップロードイベント。

  • プレフィックスが file であり、最大 100 件の結果が返されるように指定します。

    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"
    )
    
    // グローバル変数を定義します。
    var (
    	region     string // リージョン。
    	bucketName string // ソースバケットの名前。
    	objectName string // ソースオブジェクトの名前。
    
    )
    
    // init 関数は、コマンドラインパラメーターを初期化するために使用されます。
    func init() {
    	flag.StringVar(&region, "region", "", "The region in which the bucket is located.")
    	flag.StringVar(&bucketName, "bucket", "", "The name of the source bucket.")
    	flag.StringVar(&objectName, "object", "", "The name of the source object.")
    }
    
    func main() {
    	// コマンドラインパラメーターを解析します。
    	flag.Parse()
    
    	// ソースバケット名が空かどうかを確認します。
    	if len(bucketName) == 0 {
    		flag.PrintDefaults()
    		log.Fatalf("invalid parameters, source bucket name required")
    	}
    
    	// リージョンが空かどうかを確認します。
    	if len(region) == 0 {
    		flag.PrintDefaults()
    		log.Fatalf("invalid parameters, region required")
    	}
    
    	// ソースオブジェクト名が空かどうかを確認します。
    	if len(objectName) == 0 {
    		flag.PrintDefaults()
    		log.Fatalf("invalid parameters, source object name required")
    	}
    
    	// デフォルトの構成をロードし、資格情報プロバイダーとリージョンを設定します。
    	cfg := oss.LoadDefaultConfig().
    		WithCredentialsProvider(credentials.NewEnvironmentVariableCredentialsProvider()).
    		WithRegion(region)
    
    	// OSS クライアントを作成します。
    	client := oss.NewClient(cfg)
    
    	// マルチパートアップロードをリストするリクエストを作成します。
    	request := &oss.ListMultipartUploadsRequest{
    		Bucket:     oss.Ptr(bucketName), // バケットの名前。
    		MaxUploads: 100,                 // 最大 100 件の結果が返されるように指定します。
    		Prefix:     oss.Ptr("file"),     // プレフィックスが file であることを指定します。
    	}
    
    	// ページネーターを作成します。
    	p := client.NewListMultipartUploadsPaginator(request)
    
    	var i int
    	log.Println("List Multipart Uploads:")
    
    	// ページネーターの各ページを走査します。
    	for p.HasNext() {
    		i++
    
    		// 次のページのデータを取得します。
    		page, err := p.NextPage(context.TODO())
    		if err != nil {
    			log.Fatalf("failed to get page %v, %v", i, err)
    		}
    
    		// ページの各マルチパートアップロードに関する情報を出力します。
    		for _, u := range page.Uploads {
    			log.Printf("Upload key: %v, upload id: %v, initiated: %v\n", oss.ToString(u.Key), oss.ToString(u.UploadId), oss.ToTime(u.Initiated))
    		}
    	}
    
    }
    

コールバック付きのマルチパートアップロード

次のコードは、400 KB のファイルを 3 つのパートに分割し、それらを Alibaba Cloud OSS に同時にアップロードする方法を示しています。パートが完全なオブジェクトに結合された後、コールバック通知がトリガーされます。

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", "", "The region in which the bucket is located.")
	flag.StringVar(&bucketName, "bucket", "", "The name of the bucket.")
	flag.StringVar(&objectName, "object", "", "The name of the object.")
}

func main() {
	flag.Parse()
	if len(bucketName) == 0 {
		flag.PrintDefaults()
		log.Fatalf("invalid parameters, bucket name required")
	}

	if len(region) == 0 {
		flag.PrintDefaults()
		log.Fatalf("invalid parameters, region required")
	}

	if len(objectName) == 0 {
		flag.PrintDefaults()
		log.Fatalf("invalid parameters, object name required")
	}

	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)

	// コールバックパラメーターを定義します。
	callbackMap := map[string]string{
		"callbackUrl":      "https://example.com:23450",                                                                  // コールバックサーバーの URL を設定します。例: https://example.com:23450。
		"callbackBody":     "bucket=${bucket}&object=${object}&size=${size}&my_var_1=${x:my_var1}&my_var_2=${x:my_var2}", // コールバックのリクエストボディを設定します。
		"callbackBodyType": "application/x-www-form-urlencoded",                                                          // コールバックのリクエストボディのタイプを設定します。
	}

	// コールバックパラメーターを JSON に変換し、Base64 エンコーディングを実行して、パラメーターをコールバックパラメーターとして渡せるようにします。
	callbackStr, err := json.Marshal(callbackMap)
	if err != nil {
		log.Fatalf("failed to marshal callback map: %v", err)
	}
	callbackBase64 := base64.StdEncoding.EncodeToString(callbackStr)

	callbackVarMap := map[string]string{}
	callbackVarMap["x:my_var1"] = "thi is var 1"
	callbackVarMap["x:my_var2"] = "thi is var 2"
	callbackVarStr, err := json.Marshal(callbackVarMap)
	if err != nil {
		log.Fatalf("failed to 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("failed to upload part %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), // コールバックパラメーターを指定します。
		CallbackVar: oss.Ptr(callbackVarBase64),
	}
	result, err := client.CompleteMultipartUpload(context.TODO(), request)
	if err != nil {
		log.Fatalf("failed to complete multipart upload %v", err)
	}
	log.Printf("complete multipart upload result:%#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)
}

プログレスバー付きのマルチパートアップロード

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"
)

// グローバル変数を定義します。
var (
	region     string // リージョン。
	bucketName string // ソースバケットの名前。
	objectName string // ソースオブジェクトの名前。

)

// init 関数は、コマンドラインパラメーターを初期化するために使用されます。
func init() {
	flag.StringVar(&region, "region", "", "The region in which the bucket is located.")
	flag.StringVar(&bucketName, "bucket", "", "The name of the source bucket.")
	flag.StringVar(&objectName, "object", "", "The name of the source object.")
}

func main() {
	// コマンドラインパラメーターを解析します。
	flag.Parse()

	// アップロード ID を定義します。
	var uploadId string

	// ソースバケット名が空かどうかを確認します。
	if len(bucketName) == 0 {
		flag.PrintDefaults()
		log.Fatalf("invalid parameters, source bucket name required")
	}

	// リージョンが空かどうかを確認します。
	if len(region) == 0 {
		flag.PrintDefaults()
		log.Fatalf("invalid parameters, region required")
	}

	// ソースオブジェクト名が空かどうかを確認します。
	if len(objectName) == 0 {
		flag.PrintDefaults()
		log.Fatalf("invalid parameters, source object name required")
	}

	// デフォルトの構成をロードし、資格情報プロバイダーとリージョンを設定します。
	cfg := oss.LoadDefaultConfig().
		WithCredentialsProvider(credentials.NewEnvironmentVariableCredentialsProvider()).
		WithRegion(region)

	// OSS クライアントを作成します。
	client := oss.NewClient(cfg)

	// マルチパートアップロードリクエストを開始します。
	initRequest := &oss.InitiateMultipartUploadRequest{
		Bucket:  oss.Ptr(bucketName),
		Key:     oss.Ptr(objectName),
	}

	// マルチパートアップロードを開始するリクエストを実行します。
	initResult, err := client.InitiateMultipartUpload(context.TODO(), initRequest)
	if err != nil {
		log.Fatalf("failed to initiate multipart upload %v", err)
	}

	// マルチパートアップロードの開始結果を出力します。
	log.Printf("initiate multipart upload result:%#v\n", *initResult.UploadId)
	uploadId = *initResult.UploadId

	// wait group と mutex を初期化します。
	var wg sync.WaitGroup
	var parts []oss.UploadPart
	count := 5
	var mu sync.Mutex

	// ローカルファイルの内容をメモリに読み込みます。/Users/yourLocalPath/yourFileName を実際のローカルファイル名とパスに置き換えます。
	file, err := os.Open("/Users/yourLocalPath/yourFileName")
	if err != nil {
		log.Fatalf("failed to open local file %v", err)
	}
	defer file.Close()

	bufReader := bufio.NewReader(file)
	content, err := io.ReadAll(bufReader)
	if err != nil {
		log.Fatalf("failed to read local file %v", err)
	}
	log.Printf("file size: %d\n", len(content))

	// 各パートのサイズを計算します。
	chunkSize := len(content) / count
	if chunkSize == 0 {
		chunkSize = 1
	}

	// 複数のゴルーチンを開始してパートをアップロードします。
	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()

			// パートをアップロードするリクエストを作成します。
			partRequest := &oss.UploadPartRequest{
				Bucket:     oss.Ptr(bucketName),                 // 宛先バケットの名前。
				Key:        oss.Ptr(objectName),                 // 宛先オブジェクトの名前。
				PartNumber: int32(partNumber),                   // パート番号。
				UploadId:   oss.Ptr(uploadId),                   // アップロード ID。
				Body:       bytes.NewReader(content[start:end]), // パートの内容。
				ProgressFn: func(increment, transferred, total int64) {
					fmt.Printf("increment:%v, transferred:%v, total:%v\n", increment, transferred, total)
				}, // プログレスコールバック関数。アップロードの進行状況を表示するために使用されます。
			}

			// パートをアップロードするリクエストを送信します。
			partResult, err := client.UploadPart(context.TODO(), partRequest)
			if err != nil {
				log.Fatalf("failed to upload part %d: %v", partNumber, err)
			}

			log.Printf("successfully uploaded part %d (start: %d, end: %d)", partNumber, start, end)

			// パートアップロードの結果を記録します。
			part := oss.UploadPart{
				PartNumber: partRequest.PartNumber,
				ETag:       partResult.ETag,
			}

			// mutex を使用して共有データを保護します。
			mu.Lock()
			parts = append(parts, part)
			mu.Unlock()
		}(i+1, start, end)
	}

	// すべてのゴルーチンが完了するまで待ちます。
	wg.Wait()

	// マルチパートアップロードリクエストを完了します。
	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("failed to complete multipart upload %v", err)
	}

	// 完了したマルチパートアップロードの versionId を出力します。
	log.Printf("complete multipart upload result versionId:%#v\n", result)
}

関連情報

  • マルチパートアップロードの完全なサンプルコードについては、「GitHub の例」をご参照ください。

  • 完全なマルチパートアップロードの実装には、次の 3 つの API 操作が含まれます:

    • マルチパートアップロードイベントを開始するには、「InitiateMultipartUpload」をご参照ください。

    • パートをアップロードするには、「UploadPart」をご参照ください。

    • マルチパートアップロードを完了するには、「CompleteMultipartUpload」をご参照ください。

  • マルチパートアップロードイベントをキャンセルするには、「AbortMultipartUpload」をご参照ください。

  • アップロードされたパートをリストするには、「NewListPartsPaginator」をご参照ください。

  • 進行中のすべてのマルチパートアップロードイベント (開始されたが完了またはキャンセルされていないイベント) をリストするには、「NewListMultipartUploadsPaginator」をご参照ください。