全部產品
Search
文件中心

Object Storage Service:拷貝檔案(C# SDK V1)

更新時間:Nov 29, 2025

本文介紹如何在受版本控制的儲存空間(Bucket)中拷貝檔案(Object)。您可以通過CopyObject的方法拷貝小於1 GB的檔案,通過分區拷貝(UploadPartCopy)的方法拷貝大於1 GB的檔案。

注意事項

  • 本文以華東1(杭州)外網Endpoint為例。如果您希望通過與OSS同地區的其他阿里雲產品訪問OSS,請使用內網Endpoint。關於OSS支援的Region與Endpoint的對應關係,請參見地區和Endpoint

  • 本文以OSS網域名稱建立OSSClient為例。如果您希望通過自訂網域名、STS等方式建立OSSClient,請參見初始化(C# SDK V1)

  • 要拷貝檔案,您必須有oss:GetObjectoss:PutObject許可權。具體操作,請參見為RAM使用者授予自訂的權限原則

拷貝小檔案

對於小於1 GB的檔案,您可以通過CopyObject方法將檔案從一個儲存空間(源儲存空間)複製到同一地區的另一個儲存空間(目標儲存空間)。

  • x-oss-copy-source預設拷貝Object的目前的版本。如果目前的版本是刪除標記,則返回404表示該Object不存在。您可以在x-oss-copy-source中加入versionId來拷貝指定的Object版本,刪除標記不能被拷貝。

  • 您可以將Object的早期版本拷貝到同一個Bucket中,拷貝Object的歷史版本將會成為一個新的目前的版本,達到恢複Object早期版本的目的。

  • 如果目標Bucket已開啟版本控制,OSS將會為新拷貝出來的Object自動產生唯一的版本ID,此版本ID將會在響應header的x-oss-version-id中返回。如果目標Bucket未曾開啟或者暫停了版本控制,OSS將會為新拷貝的Object自動產生version ID為“null”的版本,且會覆蓋原先versionId為“null”的版本。

  • 目標Bucket在開啟或暫停版本控制狀態下,不支援對Appendable類型Object執行拷貝操作。

以下代碼用於拷貝小檔案:

using Aliyun.OSS;
using Aliyun.OSS.Common;
// yourEndpoint填寫Bucket所在地區對應的Endpoint。以華東1(杭州)為例,Endpoint填寫為https://oss-cn-hangzhou.aliyuncs.com。
var endpoint = "yourEndpoint";
// 從環境變數中擷取訪問憑證。運行本程式碼範例之前,請確保已設定環境變數OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
var accessKeyId = Environment.GetEnvironmentVariable("OSS_ACCESS_KEY_ID");
var accessKeySecret = Environment.GetEnvironmentVariable("OSS_ACCESS_KEY_SECRET");
// 填寫源Bucket名稱。
var sourceBucket = "yourSourceBucketName";
// 填寫源Object的完整路徑。Object完整路徑中不能包含Bucket名稱。
var sourceObject = "yourSourceObjectName";
// 填寫與源Bucket處於同一地區的目標Bucket名稱。
var targetBucket = "yourDestBucketName";
// 填寫目標Object的完整路徑。Object完整路徑中不能包含Bucket名稱。
var targetObject = "yourDestObjectName";
// 填寫Object的版本ID。
var versionid = "yourArchiveObjectVersionid";
// 填寫Bucket所在地區對應的Region。以華東1(杭州)為例,Region填寫為cn-hangzhou。
const string region = "cn-hangzhou";

// 建立ClientConfiguration執行個體,按照您的需要修改預設參數。
var conf = new ClientConfiguration();

// 設定v4簽名。
conf.SignatureVersion = SignatureVersion.V4;

// 建立OssClient執行個體。
var client = new OssClient(endpoint, accessKeyId, accessKeySecret, conf);
client.SetRegion(region);
try
{
    var metadata = new ObjectMetadata();
    metadata.AddHeader("mk1", "mv1");
    metadata.AddHeader("mk2", "mv2");
    var req = new CopyObjectRequest(sourceBucket, sourceObject, targetBucket, targetObject)
    {
        // 如果NewObjectMetadata為null,則為COPY模式(即拷貝源檔案的中繼資料),非null則為REPLACE模式(即覆蓋源檔案的中繼資料)。
        NewObjectMetadata = metadata, 
        // 指定Object的版本ID。
        SourceVersionId = versionid
    };
    // 拷貝檔案。
    var result = client.CopyObject(req);
    Console.WriteLine("Copy object succeeded, vesionid:{0}", result.VersionId);
}
catch (OssException ex)
{
    Console.WriteLine("Failed with error code: {0}; Error info: {1}. \nRequestID: {2} \tHostID: {3}",
        ex.ErrorCode, ex.Message, ex.RequestId, ex.HostId);
}
catch (Exception ex)
{
    Console.WriteLine("Failed with error info: {0}", ex.Message);
}

拷貝大檔案

對於大於1 GB的檔案,需要使用分區拷貝(UploadPartCopy)。

UploadPartCopy預設從一個已存在的Object的目前的版本中拷貝資料來上傳一個Part。允許通過在請求header : x-oss-copy-source中附帶versionId的子條件,實現從Object的指定版本進行拷貝,例如x-oss-copy-source : /SourceBucketName/SourceObjectName?versionId=CAEQMxiBgICAof2D0BYiIDJhMGE3N2M1YTI1NDQzOGY5NTkyNTI3MGYyMzJm****。

說明

SourceObjectName要進行URL編碼。響應中將會返回被拷貝的Object版本ID,即x-oss-copy-source-version-id。

如果未指定versionId且拷貝Object的目前的版本為刪除標記,OSS將返回404 Not Found。通過指定versionId來拷貝刪除標記時,OSS將返回400 Bad Request。

以下代碼用於分區拷貝:

using System;
using System.Collections.Generic;
using Aliyun.OSS;
using Aliyun.OSS.Common;

namespace Samples
{
    public class Program
    {
        public static void Main(string[] args)
        {
            // yourEndpoint填寫Bucket所在地區對應的Endpoint。以華東1(杭州)為例,Endpoint填寫為https://oss-cn-hangzhou.aliyuncs.com。
            var endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
            // 從環境變數中擷取訪問憑證。運行本程式碼範例之前,請確保已設定環境變數OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
            var accessKeyId = Environment.GetEnvironmentVariable("OSS_ACCESS_KEY_ID");
            var accessKeySecret = Environment.GetEnvironmentVariable("OSS_ACCESS_KEY_SECRET");
            // 填寫源Bucket名稱。
            var sourceBucket = "yourSourceBucketName";
            // 填寫源Object的完整路徑。Object完整路徑中不能包含Bucket名稱。
            var sourceObject = "yourSourceObjectName";
            // 填寫與源Bucket處於同一地區的目標Bucket名稱。
            var targetBucket = "yourDestBucketName";
            // 填寫目標Object的完整路徑。Object完整路徑中不能包含Bucket名稱。
            var targetObject = "yourDestObjectName";
            // 填寫源Object的版本ID。
            var sourceObjectVersionid = "yourSourceObjectVersionid";
            var partSize = 50 * 1024 * 1024;
            // 建立OSSClient執行個體。
            var client = new OssClient(endpoint, accessKeyId, accessKeySecret);
            try
            {
                // 初始化拷貝任務。您可以通過InitiateMultipartUploadRequest指定目標檔案中繼資料。
                var initRequest = new InitiateMultipartUploadRequest(targetBucket, targetObject);
                var result = client.InitiateMultipartUpload(initRequest);
                // 列印uploadId。
                var uploadId = result.UploadId;
                Console.WriteLine("Init multipart upload succeeded, Upload Id: {0}", result.UploadId);
                // 計算分區數。
                var request = new GetObjectMetadataRequest(sourceBucket, sourceObject)
                {
                    // 指定Object的版本ID。
                    VersionId = sourceObjectVersionid
                };
                var metadata = client.GetObjectMetadata(request);
                var fileSize = metadata.ContentLength;
                var partCount = (int)fileSize / partSize;
                if (fileSize % partSize != 0)
                {
                    partCount++;
                }
                // 開始分區拷貝。
                var partETags = new List<PartETag>();
                for (var i = 0; i < partCount; i++)
                {
                    var skipBytes = (long)partSize * i;
                    var size = (partSize < fileSize - skipBytes) ? partSize : (fileSize - skipBytes);
                    // 建立UploadPartCopyRequest。您可以通過UploadPartCopyRequest指定限定條件。
                    var uploadPartCopyRequest = new UploadPartCopyRequest(targetBucket, targetObject, sourceBucket, sourceObject, uploadId)
                    {
                        PartSize = size,
                        PartNumber = i + 1,
                        // BeginIndex用來定位此次上傳分區開始所對應的位置。
                        BeginIndex = skipBytes,
                        // 指定Object的版本ID。
                        VersionId = sourceObjectVersionid
                    };
                    // 調用uploadPartCopy方法來拷貝每一個分區。
                    var uploadPartCopyResult = client.UploadPartCopy(uploadPartCopyRequest);
                    Console.WriteLine("UploadPartCopy : {0}", i);
                    partETags.Add(uploadPartCopyResult.PartETag);
                }
                // 完成分區拷貝。
                var completeMultipartUploadRequest =
                new CompleteMultipartUploadRequest(targetBucket, targetObject, uploadId);
                // partETags為分區上傳中儲存的partETag的列表,OSS收到使用者提交的此列表後,會逐一驗證每個資料分區的有效性。全部驗證通過後,OSS會將這些分區合成一個完整的檔案。
                foreach (var partETag in partETags)
                {
                    completeMultipartUploadRequest.PartETags.Add(partETag);
                }
                var completeMultipartUploadResult = client.CompleteMultipartUpload(completeMultipartUploadRequest);
                Console.WriteLine("CompleteMultipartUpload succeeded, vesionid:{0}", completeMultipartUploadResult.VersionId);
            }
            catch (OssException ex)
            {
                Console.WriteLine("Failed with error code: {0}; Error info: {1}. \nRequestID: {2} \tHostID: {3}",
                    ex.ErrorCode, ex.Message, ex.RequestId, ex.HostId);
            }
            catch (Exception ex)
            {
                Console.WriteLine("Failed with error info: {0}", ex.Message);
            }
        }
    }
}

相關文檔

  • 關於拷貝小檔案的API介面說明,請參見CopyObject

  • 關於拷貝大檔案的API介面說明,請參見UploadPartCopy