拷贝Object

更新时间:
复制 MD 格式

拷贝Object是指在不改变文件内容的情况下,将同一地域下的源云盒Bucket内的文件复制到目标云盒Bucket,以实现数据备份、分发和灾难恢复。这有助于提高数据的可用性和冗余度,确保数据在不同Bucket之间的一致性和安全性。云盒是一种由阿里云提供的高效、可靠的数据存储和管理服务。目标Bucket应与源Bucket位于同一地域。

使用限制

不支持跨地域拷贝Object。例如,不支持将华东1(杭州)的Object拷贝到华东2(上海)。

注意事项

  • 您需要有源Object的读权限及目标Bucket的读写权限,否则无法完成拷贝操作。

  • 拷贝文件时默认会覆盖同名文件。为防止文件被意外覆盖,您可以通过以下方式保护您的文件。

    • 开启版本控制功能

      被删除或覆盖的文件会以历史版本的形式保存下来,您可以随时恢复。更多信息,请参见云盒版本控制。

    • 在拷贝请求中携带禁止覆盖同名文件的参数

      在拷贝请求的Header中携带 x-oss-forbid-overwrite参数,并指定其值为true。当您拷贝的文件在目标Bucket中存在同名文件时,该文件将拷贝失败,并返回FileAlreadyExists错误。

拷贝小文件

OSS ON云盒支持通过CopyObject接口拷贝小于1 GB的文件。

使用阿里云SDK

支持通过Java、Python、Go SDK拷贝文件(Java SDK要求3.15.0及以上版本,Python SDK V2要求1.1.1及以上版本,Go SDK V2要求v1.2.1及以上版本)。云盒场景下,Python、Go SDK的操作调用方式与公共云OSS一致,创建客户端的方式请参见SDK支持。以下代码示例分别以Java、Python、Go SDK为例。

import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSS;
import com.aliyun.oss.common.auth.*;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.model.*;
import com.aliyun.oss.common.auth.DefaultCredentialProvider;
import com.aliyun.oss.common.comm.SignVersion;
import com.aliyun.oss.ClientBuilderConfiguration;
import com.aliyun.oss.common.auth.CredentialsProviderFactory;
import com.aliyun.oss.common.auth.EnvironmentVariableCredentialsProvider;

public class Demo {
    public static void main(String[] args) throws Exception {
        // 填写云盒Bucket的数据域名。
        String endpoint = "https://cb-f8z7yvzgwfkl9q0h****.cn-hangzhou.oss-cloudbox.aliyuncs.com";
        // 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
        EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
        // 填写源云盒Bucket与目标云盒Bucket所在地域。
        String region = "cn-hangzhou";
        // 填写云盒ID。
        String cloudBoxId = "cb-f8z7yvzgwfkl9q0h****";
        // 填写源云盒Bucket名称。
        String sourceBucketName = "srcexamplebucket";
        // 填写源Object的完整路径。Object完整路径中不能包含Bucket名称。
        String sourceKey = "srcexampleobject.txt";
        // 填写与源Bucket处于同一地域的目标云盒Bucket名称。
        String destinationBucketName = "desexamplebucket";
        // 填写目标Object的完整路径,完整路径中不能包含Bucket名称。
        String destinationKey = "desexampleobject.txt";

        // 创建OSSClient实例。
        // 当OSSClient实例不再使用时,调用shutdown方法以释放资源。
        ClientBuilderConfiguration conf = new ClientBuilderConfiguration();
        conf.setSignatureVersion(SignVersion.V4);
        OSS ossClient = OSSClientBuilder.create()
                .endpoint(endpoint)
                .credentialsProvider(new DefaultCredentialProvider(credentialsProvider.getCredentials()))
                .clientConfiguration(conf)
                .region(region)
                .cloudBoxId(cloudBoxId)
                .build();

        try {
            // 创建CopyObjectRequest对象。
            CopyObjectRequest copyObjectRequest = new CopyObjectRequest(sourceBucketName, sourceKey, destinationBucketName, destinationKey);

            // 设置新的文件元数据。
            ObjectMetadata meta = new ObjectMetadata();
            meta.setContentType("text/txt");
            // 指定CopyObject操作时是否覆盖同名目标Object。此处设置为true,表示禁止覆盖同名Object。
            // meta.setHeader("x-oss-forbid-overwrite", "true");
            // 指定拷贝的源地址。
            // meta.setHeader(OSSHeaders.COPY_OBJECT_SOURCE, "/examplebucket/recode-test.txt");
            // 如果源Object的ETag值和您提供的ETag相等,则执行拷贝操作,并返回200 OK。
            // meta.setHeader(OSSHeaders.COPY_OBJECT_SOURCE_IF_MATCH, "5B3C1A2E053D763E1B002CC607C5****");
            // 如果源Object的ETag值和您提供的ETag不相等,则执行拷贝操作,并返回200 OK。
            // meta.setHeader(OSSHeaders.COPY_OBJECT_SOURCE_IF_NONE_MATCH, "5B3C1A2E053D763E1B002CC607C5****");
            // 如果指定的时间等于或者晚于文件实际修改时间,则正常拷贝文件,并返回200 OK。
            // meta.setHeader(OSSHeaders.COPY_OBJECT_SOURCE_IF_UNMODIFIED_SINCE, "2021-12-09T07:01:56.000Z");
            // 如果源Object在指定时间后被修改过,则执行拷贝操作。
            // meta.setHeader(OSSHeaders.COPY_OBJECT_SOURCE_IF_MODIFIED_SINCE, "2021-12-09T07:01:56.000Z");
            // 指定设置目标Object元数据的方式。此处设置为COPY,表示复制源Object的元数据到目标Object。
            // meta.setHeader(OSSHeaders.COPY_OBJECT_METADATA_DIRECTIVE, "COPY");
            // 指定OSS创建目标Object时使用的服务器端加密算法。
            // meta.setHeader(OSSHeaders.OSS_SERVER_SIDE_ENCRYPTION, ObjectMetadata.KMS_SERVER_SIDE_ENCRYPTION);
            // 表示KMS托管的用户主密钥,该参数仅在x-oss-server-side-encryption为KMS时有效。
            // meta.setHeader(OSSHeaders.OSS_SERVER_SIDE_ENCRYPTION_KEY_ID, "9468da86-3509-4f8d-a61e-6eab1eac****");
            // 指定OSS创建目标Object时的访问权限,此处设置为Private,表示只有Object的拥有者和授权用户有该Object的读写权限,其他用户没有权限操作该Object。
            // meta.setHeader(OSSHeaders.OSS_OBJECT_ACL, CannedAccessControlList.Private);
            // 指定Object的存储类型。此处设置为Standard,表示标准存储类型。
            // meta.setHeader(OSSHeaders.OSS_STORAGE_CLASS, StorageClass.Standard);
            // 指定Object的对象标签,可同时设置多个标签。
            // meta.setHeader(OSSHeaders.OSS_TAGGING, "a:1");
            // 指定设置目标Object对象标签的方式。此处设置为COPY,表示复制源Object的对象标签到目标Object。
            // meta.setHeader(OSSHeaders.COPY_OBJECT_TAGGING_DIRECTIVE, "COPY");
            copyObjectRequest.setNewObjectMetadata(meta);

            // 复制文件。
            CopyObjectResult result = ossClient.copyObject(copyObjectRequest);
            System.out.println("ETag: " + result.getETag() + " LastModified: " + result.getLastModified());
        } catch (OSSException oe) {
            System.out.println("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            System.out.println("Error Message:" + oe.getErrorMessage());
            System.out.println("Error Code:" + oe.getErrorCode());
            System.out.println("Request ID:" + oe.getRequestId());
            System.out.println("Host ID:" + oe.getHostId());
        } catch (ClientException ce) {
            System.out.println("Caught an ClientException, which means the client encountered "
                    + "a serious internal problem while trying to communicate with OSS, "
                    + "such as not being able to access the network.");
            System.out.println("Error Message:" + ce.getMessage());
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
    }
}
# -*- coding: utf-8 -*-
import alibabacloud_oss_v2 as oss

# 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
credentials_provider = oss.credentials.EnvironmentVariableCredentialsProvider()

# 使用SDK的默认配置。
cfg = oss.config.load_default()
cfg.credentials_provider = credentials_provider

# 设置Region为云盒所在的地域,例如cn-hangzhou。
cfg.region = "cn-hangzhou"

# 设置云盒ID。设置云盒ID后,SDK会自动将签名产品切换为oss-cloudbox。
cfg.cloud_box_id = "cb-f8z7yvzgwfkl9q0h****"

# 设置访问域名,格式为CloudboxId.Region.oss-cloudbox.aliyuncs.com。
cfg.endpoint = "cb-f8z7yvzgwfkl9q0h****.cn-hangzhou.oss-cloudbox.aliyuncs.com"

# 创建OSS客户端。
client = oss.Client(cfg)

# 填写源云盒Bucket名称,例如srcexamplebucket。
source_bucket_name = "srcexamplebucket"
# 填写源Object的完整路径,Object完整路径中不能包含Bucket名称。
source_key = "srcexampleobject.txt"
# 填写与源Bucket处于同一地域的目标云盒Bucket名称,例如desexamplebucket。
dest_bucket_name = "desexamplebucket"
# 填写目标Object的完整路径,完整路径中不能包含Bucket名称。
dest_key = "desexampleobject.txt"

# 拷贝文件。
result = client.copy_object(oss.CopyObjectRequest(
    bucket=dest_bucket_name,
    key=dest_key,
    source_bucket=source_bucket_name,
    source_key=source_key,
))
print(f'ETag: {result.etag}, LastModified: {result.last_modified}')
package main

import (
	"context"
	"log"

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

func main() {
	// 加载SDK的默认配置,并设置访问凭证、地域、云盒ID及访问域名。
	// 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
	cfg := oss.LoadDefaultConfig().
		WithCredentialsProvider(credentials.NewEnvironmentVariableCredentialsProvider()).
		// 设置Region为云盒所在的地域,例如cn-hangzhou。
		WithRegion("cn-hangzhou").
		// 设置访问域名,格式为CloudboxId.Region.oss-cloudbox.aliyuncs.com。
		WithEndpoint("cb-f8z7yvzgwfkl9q0h****.cn-hangzhou.oss-cloudbox.aliyuncs.com").
		// 设置云盒ID。设置云盒ID后,SDK会自动将签名产品切换为oss-cloudbox。
		WithCloudBoxId("cb-f8z7yvzgwfkl9q0h****")

	// 创建OSS客户端。
	client := oss.NewClient(cfg)

	// 填写源云盒Bucket名称,例如srcexamplebucket。
	sourceBucketName := "srcexamplebucket"
	// 填写源Object的完整路径,Object完整路径中不能包含Bucket名称。
	sourceKey := "srcexampleobject.txt"
	// 填写与源Bucket处于同一地域的目标云盒Bucket名称,例如desexamplebucket。
	destBucketName := "desexamplebucket"
	// 填写目标Object的完整路径,完整路径中不能包含Bucket名称。
	destKey := "desexampleobject.txt"

	// 拷贝文件。
	result, err := client.CopyObject(context.TODO(), &oss.CopyObjectRequest{
		Bucket:       oss.Ptr(destBucketName),
		Key:          oss.Ptr(destKey),
		SourceBucket: oss.Ptr(sourceBucketName),
		SourceKey:    oss.Ptr(sourceKey),
	})
	if err != nil {
		log.Fatalf("failed to copy object %v", err)
	}
	log.Printf("ETag: %v, LastModified: %v\n", oss.ToString(result.ETag), oss.ToTime(result.LastModified))
}

使用命令行管理工具ossutil

关于使用ossutil拷贝小文件的具体操作,请参见cp(拷贝文件)。

拷贝大文件

OSS ON云盒支持通过UploadPartCopy接口拷贝大于1 GB的文件。

使用阿里云SDK

支持通过Java、Python、Go SDK拷贝文件(Java SDK要求3.15.0及以上版本,Python SDK V2要求1.1.1及以上版本,Go SDK V2要求v1.2.1及以上版本)。云盒场景下,Python、Go SDK的操作调用方式与公共云OSS一致,创建客户端的方式请参见SDK支持。以下代码示例分别以Java、Python、Go SDK为例。

import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSS;
import com.aliyun.oss.common.auth.*;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.model.*;
import java.util.ArrayList;
import java.util.List;
import com.aliyun.oss.common.auth.DefaultCredentialProvider;
import com.aliyun.oss.common.comm.SignVersion;
import com.aliyun.oss.ClientBuilderConfiguration;
import com.aliyun.oss.common.auth.CredentialsProviderFactory;
import com.aliyun.oss.common.auth.EnvironmentVariableCredentialsProvider;

public class Demo {
    public static void main(String[] args) throws Exception {
        // 填写云盒Bucket的数据域名。
        String endpoint = "https://cb-f8z7yvzgwfkl9q0h****.cn-hangzhou.oss-cloudbox.aliyuncs.com";
        // 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
        EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
        // 填写源云盒Bucket与目标云盒Bucket所在地域。
        String region = "cn-hangzhou";
        // 填写云盒ID。
        String cloudBoxId = "cb-f8z7yvzgwfkl9q0h****";
        // 填写源云盒Bucket名称。
        String sourceBucketName = "srcexamplebucket";
        // 填写源Object的完整路径。Object完整路径中不能包含Bucket名称。
        String sourceKey = "srcexampleobject.txt";
        // 填写与源Bucket处于同一地域的目标云盒Bucket名称。
        String destinationBucketName = "desexamplebucket";
        // 填写目标Object的完整路径。Object完整路径中不能包含Bucket名称。
        String destinationKey = "desexampleobject.txt";

        // 创建OSSClient实例。
        // 当OSSClient实例不再使用时,调用shutdown方法以释放资源。
        ClientBuilderConfiguration conf = new ClientBuilderConfiguration();
        conf.setSignatureVersion(SignVersion.V4);
        OSS ossClient = OSSClientBuilder.create()
                .endpoint(endpoint)
                .credentialsProvider(new DefaultCredentialProvider(credentialsProvider.getCredentials()))
                .clientConfiguration(conf)
                .region(region)
                .cloudBoxId(cloudBoxId)
                .build();

        try {
            ObjectMetadata objectMetadata = ossClient.getObjectMetadata(sourceBucketName, sourceKey);
            // 获取被拷贝文件的大小。
            long contentLength = objectMetadata.getContentLength();

            // 设置分片大小为10 MB。单位为字节。
            long partSize = 1024 * 1024 * 10;

            // 计算分片总数。
            int partCount = (int) (contentLength / partSize);
            if (contentLength % partSize != 0) {
                partCount++;
            }
            System.out.println("total part count:" + partCount);

            // 初始化拷贝任务。可以通过InitiateMultipartUploadRequest指定目标文件元数据。
            InitiateMultipartUploadRequest initiateMultipartUploadRequest = new InitiateMultipartUploadRequest(destinationBucketName, destinationKey);
            InitiateMultipartUploadResult initiateMultipartUploadResult = ossClient.initiateMultipartUpload(initiateMultipartUploadRequest);
            String uploadId = initiateMultipartUploadResult.getUploadId();

            // 分片拷贝。
            List<PartETag> partETags = new ArrayList<PartETag>();
            for (int i = 0; i < partCount; i++) {
                // 计算每个分片的大小。
                long skipBytes = partSize * i;
                long size = partSize < contentLength - skipBytes ? partSize : contentLength - skipBytes;

                // 创建UploadPartCopyRequest。可以通过UploadPartCopyRequest指定限定条件。
                UploadPartCopyRequest uploadPartCopyRequest =
                        new UploadPartCopyRequest(sourceBucketName, sourceKey, destinationBucketName, destinationKey);
                uploadPartCopyRequest.setUploadId(uploadId);
                uploadPartCopyRequest.setPartSize(size);
                uploadPartCopyRequest.setBeginIndex(skipBytes);
                uploadPartCopyRequest.setPartNumber(i + 1);
                UploadPartCopyResult uploadPartCopyResult = ossClient.uploadPartCopy(uploadPartCopyRequest);

                // 将返回的分片ETag保存到partETags中。
                partETags.add(uploadPartCopyResult.getPartETag());
            }

            // 提交分片拷贝任务。
            CompleteMultipartUploadRequest completeMultipartUploadRequest = new CompleteMultipartUploadRequest(
                    destinationBucketName, destinationKey, uploadId, partETags);
            ossClient.completeMultipartUpload(completeMultipartUploadRequest);
        } catch (OSSException oe) {
            System.out.println("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            System.out.println("Error Message:" + oe.getErrorMessage());
            System.out.println("Error Code:" + oe.getErrorCode());
            System.out.println("Request ID:" + oe.getRequestId());
            System.out.println("Host ID:" + oe.getHostId());
        } catch (ClientException ce) {
            System.out.println("Caught an ClientException, which means the client encountered "
                    + "a serious internal problem while trying to communicate with OSS, "
                    + "such as not being able to access the network.");
            System.out.println("Error Message:" + ce.getMessage());
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
    }
}     
# -*- coding: utf-8 -*-
import alibabacloud_oss_v2 as oss

# 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
credentials_provider = oss.credentials.EnvironmentVariableCredentialsProvider()

# 使用SDK的默认配置。
cfg = oss.config.load_default()
cfg.credentials_provider = credentials_provider

# 设置Region为云盒所在的地域,例如cn-hangzhou。
cfg.region = "cn-hangzhou"

# 设置云盒ID。设置云盒ID后,SDK会自动将签名产品切换为oss-cloudbox。
cfg.cloud_box_id = "cb-f8z7yvzgwfkl9q0h****"

# 设置访问域名,格式为CloudboxId.Region.oss-cloudbox.aliyuncs.com。
cfg.endpoint = "cb-f8z7yvzgwfkl9q0h****.cn-hangzhou.oss-cloudbox.aliyuncs.com"

# 创建OSS客户端。
client = oss.Client(cfg)

# 填写源云盒Bucket名称,例如srcexamplebucket。
source_bucket_name = "srcexamplebucket"
# 填写源Object的完整路径,Object完整路径中不能包含Bucket名称。
source_key = "srcexampleobject.txt"
# 填写与源Bucket处于同一地域的目标云盒Bucket名称,例如desexamplebucket。
dest_bucket_name = "desexamplebucket"
# 填写目标Object的完整路径,完整路径中不能包含Bucket名称。
dest_key = "desexampleobject.txt"

# 获取被拷贝文件的大小。
result_meta = client.get_object_meta(oss.GetObjectMetaRequest(
    bucket=source_bucket_name,
    key=source_key,
))
total_size = result_meta.content_length

# 设置分片大小为10 MB。单位为字节。
part_size = 10 * 1024 * 1024

# 初始化拷贝任务,返回的upload_id是分片上传事件的唯一标识。
init_result = client.initiate_multipart_upload(oss.InitiateMultipartUploadRequest(
    bucket=dest_bucket_name,
    key=dest_key,
))
upload_id = init_result.upload_id

# 分片拷贝。
part_number = 1
upload_parts = []
offset = 0
while offset < total_size:
    num_to_upload = min(part_size, total_size - offset)
    end = offset + num_to_upload - 1
    up_result = client.upload_part_copy(oss.UploadPartCopyRequest(
        bucket=dest_bucket_name,
        key=dest_key,
        upload_id=upload_id,
        part_number=part_number,
        source_bucket=source_bucket_name,
        source_key=source_key,
        source_range='bytes=' + str(offset) + '-' + str(end),
    ))
    # 将返回的分片ETag保存到upload_parts中。
    upload_parts.append(oss.UploadPart(part_number=part_number, etag=up_result.etag))
    offset += num_to_upload
    part_number += 1

# 按分片号从小到大排序。
parts = sorted(upload_parts, key=lambda p: p.part_number)

# 提交分片拷贝任务。
result = client.complete_multipart_upload(oss.CompleteMultipartUploadRequest(
    bucket=dest_bucket_name,
    key=dest_key,
    upload_id=upload_id,
    complete_multipart_upload=oss.CompleteMultipartUpload(
        parts=parts
    ),
))
print(f'etag: {result.etag}')
package main

import (
	"context"
	"fmt"
	"log"

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

func main() {
	// 加载SDK的默认配置,并设置访问凭证、地域、云盒ID及访问域名。
	// 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
	cfg := oss.LoadDefaultConfig().
		WithCredentialsProvider(credentials.NewEnvironmentVariableCredentialsProvider()).
		// 设置Region为云盒所在的地域,例如cn-hangzhou。
		WithRegion("cn-hangzhou").
		// 设置访问域名,格式为CloudboxId.Region.oss-cloudbox.aliyuncs.com。
		WithEndpoint("cb-f8z7yvzgwfkl9q0h****.cn-hangzhou.oss-cloudbox.aliyuncs.com").
		// 设置云盒ID。设置云盒ID后,SDK会自动将签名产品切换为oss-cloudbox。
		WithCloudBoxId("cb-f8z7yvzgwfkl9q0h****")

	// 创建OSS客户端。
	client := oss.NewClient(cfg)

	// 填写源云盒Bucket名称,例如srcexamplebucket。
	sourceBucketName := "srcexamplebucket"
	// 填写源Object的完整路径,Object完整路径中不能包含Bucket名称。
	sourceKey := "srcexampleobject.txt"
	// 填写与源Bucket处于同一地域的目标云盒Bucket名称,例如desexamplebucket。
	destBucketName := "desexamplebucket"
	// 填写目标Object的完整路径,完整路径中不能包含Bucket名称。
	destKey := "desexampleobject.txt"

	// 获取被拷贝文件的大小。
	headResult, err := client.HeadObject(context.TODO(), &oss.HeadObjectRequest{
		Bucket: oss.Ptr(sourceBucketName),
		Key:    oss.Ptr(sourceKey),
	})
	if err != nil {
		log.Fatalf("failed to head object %v", err)
	}
	total := headResult.ContentLength

	// 设置分片大小为10 MB。单位为字节。
	partSize := int64(10 * 1024 * 1024)

	// 计算分片总数。
	partCount := int((total + partSize - 1) / partSize)

	// 初始化拷贝任务,返回的UploadId是分片上传事件的唯一标识。
	initResult, err := client.InitiateMultipartUpload(context.TODO(), &oss.InitiateMultipartUploadRequest{
		Bucket: oss.Ptr(destBucketName),
		Key:    oss.Ptr(destKey),
	})
	if err != nil {
		log.Fatalf("failed to initiate multipart upload %v", err)
	}
	uploadId := initResult.UploadId

	// 分片拷贝。
	var parts []oss.UploadPart
	for i := 0; i < partCount; i++ {
		start := int64(i) * partSize
		end := start + partSize - 1
		if end > total-1 {
			end = total - 1
		}
		partRequest := &oss.UploadPartCopyRequest{
			Bucket:       oss.Ptr(destBucketName),
			Key:          oss.Ptr(destKey),
			SourceBucket: oss.Ptr(sourceBucketName),
			SourceKey:    oss.Ptr(sourceKey),
			PartNumber:   int32(i + 1),
			UploadId:     uploadId,
			Range:        oss.Ptr(fmt.Sprintf("bytes=%d-%d", start, end)),
		}
		partResult, err := client.UploadPartCopy(context.TODO(), partRequest)
		if err != nil {
			log.Fatalf("failed to upload part copy %v", err)
		}
		// 将返回的分片ETag保存到parts中。
		parts = append(parts, oss.UploadPart{
			PartNumber: partRequest.PartNumber,
			ETag:       partResult.ETag,
		})
	}

	// 提交分片拷贝任务。
	result, err := client.CompleteMultipartUpload(context.TODO(), &oss.CompleteMultipartUploadRequest{
		Bucket:   oss.Ptr(destBucketName),
		Key:      oss.Ptr(destKey),
		UploadId: uploadId,
		CompleteMultipartUpload: &oss.CompleteMultipartUpload{
			Parts: parts,
		},
	})
	if err != nil {
		log.Fatalf("failed to complete multipart upload %v", err)
	}
	log.Printf("etag: %v\n", oss.ToString(result.ETag))
}

使用命令行管理工具ossutil

关于使用ossutil拷贝大文件的具体操作,请参见cp(拷贝文件)。

使用REST API

如果您的程序自定义要求较高,您可以直接发起REST API请求。直接发起REST API请求需要手动编写代码计算签名。更多信息,请参见UploadPartCopy。