このトピックでは、Object Storage Service (OSS) SDK for Go 2.0 の UploadPartCopy 操作を呼び出して、マルチパートコピーを使用して、同じリージョン内のソースバケットから宛先バケットにオブジェクトをコピーする方法について説明します。宛先バケットは、ソースバケットと同じでも、別のバケットでもかまいません。
使用上の注意
このトピックのサンプルコードでは、中国 (杭州) リージョン (
cn-hangzhou) を例として使用し、デフォルトでパブリックエンドポイントを使用します。同じリージョン内の他の Alibaba Cloud サービスから OSS にアクセスする場合は、内部エンドポイントを使用します。OSS がサポートするリージョンとエンドポイントの詳細については、「リージョンとエンドポイント」をご参照ください。このトピックでは、アクセス資格情報は環境変数から取得されます。アクセス資格情報の設定方法の詳細については、「アクセス資格情報の設定」をご参照ください。
オブジェクトをコピーするには、ソースオブジェクトに対する読み取り権限と、宛先バケットに対する読み取りおよび書き込み権限が必要です。
ソースバケットと宛先バケットは、同じリージョンに配置する必要があります。たとえば、中国 (杭州) リージョンにあるバケット内のオブジェクトを、中国 (青島) リージョンにある別のバケットにコピーすることはできません。
ソースバケットと宛先バケットにリテンションポリシーが設定されていないことを確認してください。設定されている場合、The object you specified is immutable. というエラーメッセージが返されます。
メソッド
func (c *Client) UploadPartCopy(ctx context.Context, request *UploadPartCopyRequest, optFns ...func(*Options)) (*UploadPartCopyResult, error)リクエストパラメーター
パラメーター | タイプ | 説明 |
ctx | context.Context | リクエストのコンテキスト。リクエストの合計期間を指定するために使用できます。 |
request | *UploadPartCopyRequest | 特定の API 操作のパラメーター。詳細については、「UploadPartCopyRequest」をご参照ください。 |
optFns | ...func(*Options) | オプションのパラメーター。詳細については、「Options」をご参照ください。 |
応答パラメーター
パラメーター | タイプ | 説明 |
result | *UploadPartCopyResult | 操作への応答。このパラメーターは、err の値が nil の場合に有効です。詳細については、「UploadPartCopyResult」をご参照ください。 |
err | error | リクエストのステータス。リクエストが失敗した場合、err の値は nil 以外になります。 |
マルチパートコピーのプロセス
シャーディングされたコピーには、次の 3 つのステップが含まれます:
マルチパートアップロードタスクを開始します。
Client.InitiateMultipartUpload メソッドを使用して、OSS で一意のアップロード ID を取得します。
パートをアップロードします。
Client.UploadPartCopy メソッドを使用してパートをアップロードします。
説明特定のアップロード ID を持つマルチパートアップロードタスクを実行してアップロードされたパートの場合、パート番号はオブジェクト内の相対的な位置を識別します。パートをアップロードし、そのパート番号を再利用して別のパートをアップロードすると、新しいパートが元のパートを上書きします。
OSS は、アップロードされた各パートの MD5 ハッシュを応答の ETag ヘッダーに含めます。
OSS は、アップロードされたパートの MD5 ハッシュを計算し、その MD5 ハッシュを OSS SDK for Go によって計算された MD5 ハッシュと比較します。2 つのハッシュが異なる場合、OSS は InvalidDigest エラーコードを返します。
マルチパートアップロードタスクを完了します。
すべてのパートがアップロードされた後、Client.CompleteMultipartUpload メソッドを使用してこれらのパートを完全なオブジェクトに結合します。
例
次のサンプルコードは、マルチパートコピーを使用してソースバケットから宛先バケットにオブジェクトをコピーし、パートを結合して完全なオブジェクトにする方法の例を示しています:
package main
import (
"context"
"flag"
"log"
"sync"
"github.com/aliyun/alibabacloud-oss-go-sdk-v2/oss"
"github.com/aliyun/alibabacloud-oss-go-sdk-v2/oss/credentials"
)
// グローバル変数を指定します。
var (
region string // リージョン。
srcBucketName string // ソースバケットの名前。
srcObjectName string // ソースオブジェクトの名前。
destBucketName string // 宛先バケットの名前。
destObjectName string // 宛先オブジェクトの名前。
)
// コマンドラインパラメーターを初期化するために使用される init 関数を指定します。
func init() {
flag.StringVar(®ion, "region", "", "The region in which the bucket is located.")
flag.StringVar(&srcBucketName, "src-bucket", "", "The name of the source bucket.")
flag.StringVar(&srcObjectName, "src-object", "", "The name of the source object.")
flag.StringVar(&destBucketName, "dest-bucket", "", "The name of the destination bucket.")
flag.StringVar(&destObjectName, "dest-object", "", "The name of the destination object.")
}
func main() {
// コマンドラインパラメーターを解析します。
flag.Parse()
// アップロード ID を指定します。
var uploadId string
// ソースバケット名が空かどうかを確認します。
if len(srcBucketName) == 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(destBucketName) == 0 {
destBucketName = srcBucketName
}
// ソースオブジェクト名が空かどうかを確認します。
if len(srcObjectName) == 0 {
flag.PrintDefaults()
log.Fatalf("invalid parameters, source object name required")
}
// 宛先オブジェクト名が空かどうかを確認します。
if len(destObjectName) == 0 {
flag.PrintDefaults()
log.Fatalf("invalid parameters, destination object name required")
}
// デフォルト設定をロードし、資格情報プロバイダーとリージョンを指定します。
cfg := oss.LoadDefaultConfig().
WithCredentialsProvider(credentials.NewEnvironmentVariableCredentialsProvider()).
WithRegion(region)
// OSS クライアントを作成します。
client := oss.NewClient(cfg)
// マルチパートアップロードリクエストを初期化します。
initRequest := &oss.InitiateMultipartUploadRequest{
Bucket: oss.Ptr(destBucketName),
Key: oss.Ptr(destObjectName),
}
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
// マルチパートアップロードのために複数のゴルーチンを開始します。
for i := 0; i < count; i++ {
wg.Add(1)
go func(partNumber int, i int) {
defer wg.Done()
// マルチパートアップロードリクエストを作成します。
partRequest := &oss.UploadPartCopyRequest{
Bucket: oss.Ptr(destBucketName), // 宛先バケットの名前。
Key: oss.Ptr(destObjectName), // 宛先オブジェクトの名前。
SourceBucket: oss.Ptr(srcBucketName), // ソースバケットの名前。
SourceKey: oss.Ptr(srcObjectName), // ソースオブジェクトの名前。
PartNumber: int32(partNumber), // パート番号。
const uploadId = '<Upload Id>'; // マルチパートアップロードタスクのアップロード ID。
}
// マルチパートアップロードリクエストを送信します。
partResult, err := client.UploadPartCopy(context.TODO(), partRequest)
if err != nil {
log.Fatalf("failed to upload part copy %d: %v", partNumber, err)
}
// マルチパートアップロードの結果を記録します。
part := oss.UploadPart{
PartNumber: partRequest.PartNumber,
ETag: partResult.ETag,
}
// mutex を使用して共有データを保護します。
mu.Lock()
parts = append(parts, part)
mu.Unlock()
}(i+1, i)
}
// すべてのゴルーチンが完了するまで待ちます。
wg.Wait()
// マルチパートアップロードリクエストを完了します。
request := &oss.CompleteMultipartUploadRequest{
Bucket: oss.Ptr(destBucketName),
Key: oss.Ptr(destObjectName),
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)
}
関連ドキュメント
マルチパートコピーを使用してオブジェクトをコピーするために使用される完全なサンプルコードについては、GitHub をご参照ください。
マルチパートアップロードタスクを開始するために呼び出すことができる API 操作の詳細については、「InitiateMultipartUpload」をご参照ください。
マルチパートコピーを使用してオブジェクトをコピーするために呼び出すことができる API 操作の詳細については、「UploadPartCopy」をご参照ください。
マルチパートアップロードタスクを完了するために呼び出すことができる API 操作の詳細については、「CompleteMultipartUpload」をご参照ください。