Copy objects in a versioning-enabled OSS bucket using CopyObject (objects up to 1 GB) or UploadPartCopy with multipart copy (objects larger than 1 GB).
Prerequisites
Before you begin, ensure that you have:
An OSS bucket with versioning enabled
The
oss:GetObjectandoss:PutObjectpermissions on the source and destination buckets. For details, see Attach a custom policy to a RAM userThe
OSS_ACCESS_KEY_IDandOSS_ACCESS_KEY_SECRETenvironment variables set with your AccessKey credentials
Usage notes
The examples in this topic use the public endpoint for the China (Hangzhou) region. To access OSS from another Alibaba Cloud service in the same region, use an internal endpoint instead. For a full list of endpoints, see Regions and endpoints.
The code examples create an
OssClientinstance using an OSS endpoint. To create an instance using a custom domain name or Security Token Service (STS), see Initialization.
Copy a small object
Use CopyObject to copy an object up to 1 GB in size between buckets in the same region.
How versioning affects the copy operation:
By default,
CopyObjectcopies the current version of the source object. If the current version is a delete marker, OSS returns HTTP 404 (object not found). To copy a specific version, includeversionIdin thex-oss-copy-sourcerequest header.Delete markers cannot be copied.
Copying a previous version to the same bucket promotes it to the current version, effectively restoring it.
If the destination bucket has versioning enabled, OSS assigns a unique version ID to the destination object and returns it in the
x-oss-version-idresponse header.If the destination bucket has versioning disabled or suspended, OSS creates a version with ID
nulland overwrites any existingnullversion.Appendable objects cannot be copied to a bucket with versioning enabled or suspended.
Metadata copy behavior:
Set
NewObjectMetadatatonullto use COPY mode — the source object's metadata is copied to the destination object.Set
NewObjectMetadatato a non-null value to use REPLACE mode — the specified metadata replaces the source object's metadata.
using Aliyun.OSS;
using Aliyun.OSS.Common;
// Specify the endpoint for the region where your bucket is located.
// Example: https://oss-cn-hangzhou.aliyuncs.com for China (Hangzhou).
var endpoint = "yourEndpoint";
// Read AccessKey credentials from environment variables.
var accessKeyId = Environment.GetEnvironmentVariable("OSS_ACCESS_KEY_ID");
var accessKeySecret = Environment.GetEnvironmentVariable("OSS_ACCESS_KEY_SECRET");
// Source bucket and object.
var sourceBucket = "yourSourceBucketName";
var sourceObject = "yourSourceObjectName"; // Full path, excluding the bucket name.
// Destination bucket and object. The destination bucket must be in the same region.
var targetBucket = "yourDestBucketName";
var targetObject = "yourDestObjectName"; // Full path, excluding the bucket name.
// Version ID of the source object to copy.
var versionid = "yourArchiveObjectVersionid";
// Region identifier, e.g., cn-hangzhou for China (Hangzhou).
const string region = "cn-hangzhou";
// Configure the client to use signature algorithm V4.
var conf = new ClientConfiguration();
conf.SignatureVersion = SignatureVersion.V4;
// Create the OssClient instance.
var client = new OssClient(endpoint, accessKeyId, accessKeySecret, conf);
client.SetRegion(region);
try
{
// Define destination object metadata (REPLACE mode).
// Set NewObjectMetadata to null to copy source metadata instead (COPY mode).
var metadata = new ObjectMetadata();
metadata.AddHeader("mk1", "mv1");
metadata.AddHeader("mk2", "mv2");
var req = new CopyObjectRequest(sourceBucket, sourceObject, targetBucket, targetObject)
{
NewObjectMetadata = metadata,
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);
}Copy a large object
For objects larger than 1 GB, use multipart copy with UploadPartCopy. The operation splits the source object into parts and copies each part independently.
How versioning affects the copy operation:
By default,
UploadPartCopycopies the current version of the source object. To copy a specific version, add the version ID to thex-oss-copy-sourcerequest header. For example:x-oss-copy-source: /SourceBucketName/SourceObjectName?versionId=CAEQMxiBgICAof2D0BYiIDJhMGE3N2M1YTI1NDQzOGY5NTkyNTI3MGYyMzJm****The
SourceObjectNameparameter must be URL-encoded.The version ID of the copied object is returned in the
x-oss-copy-source-version-idresponse header.If no version ID is specified and the current version is a delete marker, OSS returns 404 Not Found.
If a version ID is specified and that version is a delete marker, OSS returns 400 Bad Request.
Multipart copy steps:
Initiate — call
InitiateMultipartUploadto start the task and get an upload ID.Get metadata — call
GetObjectMetadatato retrieve the source object size.Split and copy — divide the object into 50 MB parts and call
UploadPartCopyfor each part, collecting the returnedPartETagvalues.Complete — call
CompleteMultipartUploadwith the collectedPartETaglist to assemble the final object.
using System;
using System.Collections.Generic;
using Aliyun.OSS;
using Aliyun.OSS.Common;
namespace Samples
{
public class Program
{
public static void Main(string[] args)
{
var endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
// Read AccessKey credentials from environment variables.
var accessKeyId = Environment.GetEnvironmentVariable("OSS_ACCESS_KEY_ID");
var accessKeySecret = Environment.GetEnvironmentVariable("OSS_ACCESS_KEY_SECRET");
// Source bucket and object.
var sourceBucket = "yourSourceBucketName";
var sourceObject = "yourSourceObjectName"; // Full path, excluding the bucket name.
// Destination bucket and object. Must be in the same region as the source.
var targetBucket = "yourDestBucketName";
var targetObject = "yourDestObjectName"; // Full path, excluding the bucket name.
// Version ID of the source object to copy.
var sourceObjectVersionid = "yourSourceObjectVersionid";
var partSize = 50 * 1024 * 1024; // 50 MB per part.
var client = new OssClient(endpoint, accessKeyId, accessKeySecret);
try
{
// Step 1: Initiate the multipart copy task.
var initRequest = new InitiateMultipartUploadRequest(targetBucket, targetObject);
var result = client.InitiateMultipartUpload(initRequest);
var uploadId = result.UploadId;
Console.WriteLine("Init multipart upload succeeded, Upload Id: {0}", uploadId);
// Step 2: Retrieve the source object size.
var metadataRequest = new GetObjectMetadataRequest(sourceBucket, sourceObject)
{
VersionId = sourceObjectVersionid
};
var metadata = client.GetObjectMetadata(metadataRequest);
var fileSize = metadata.ContentLength;
// Calculate the number of parts.
var partCount = (int)fileSize / partSize;
if (fileSize % partSize != 0)
{
partCount++;
}
// Step 3: Copy each part.
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);
var uploadPartCopyRequest = new UploadPartCopyRequest(
targetBucket, targetObject, sourceBucket, sourceObject, uploadId)
{
PartSize = size,
PartNumber = i + 1,
BeginIndex = skipBytes, // Start byte position for this part.
VersionId = sourceObjectVersionid
};
var uploadPartCopyResult = client.UploadPartCopy(uploadPartCopyRequest);
Console.WriteLine("UploadPartCopy : {0}", i);
partETags.Add(uploadPartCopyResult.PartETag);
}
// Step 4: Complete the multipart copy.
// OSS verifies each part against its ETag, then assembles the final object.
var completeRequest = new CompleteMultipartUploadRequest(targetBucket, targetObject, uploadId);
foreach (var partETag in partETags)
{
completeRequest.PartETags.Add(partETag);
}
var completeResult = client.CompleteMultipartUpload(completeRequest);
Console.WriteLine("CompleteMultipartUpload succeeded, vesionid:{0}", completeResult.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);
}
}
}
}References
CopyObject — API reference for copying small objects
UploadPartCopy — API reference for copying large objects using multipart copy