全部產品
Search
文件中心

Object Storage Service:拷貝Object

更新時間:Aug 08, 2025

拷貝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的檔案。

使用Java SDK

僅支援通過Java SDK拷貝檔案,Java SDK要求3.15.0及以上版本。

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();
            }
        }
    }
}

使用命令列管理工具ossutil

關於使用ossutil拷貝小檔案的具體操作,請參見cp(拷貝檔案)

拷貝大檔案

OSS ON雲盒支援通過UploadPartCopy介面拷貝大於1 GB的檔案。

使用Java SDK

僅支援通過Java SDK拷貝檔案,Java SDK要求3.15.0及以上版本。

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();
            }
        }
    }
}     

使用命令列管理工具ossutil

關於使用ossutil拷貝大檔案的具體操作,請參見cp(拷貝檔案)

使用REST API

如果您的程式自訂要求較高,您可以直接發起REST API請求。直接發起REST API請求需要手動編寫代碼計算簽名。更多資訊,請參見UploadPartCopy