This topic describes how to copy objects in a versioned bucket. You can use CopyObject to copy an object that is up to 1 GB in size and use UploadPartCopy to copy an object larger than 1 GB.

Copy a small object

You can use CopyObject to copy an object that is up to 1 GB in size from a source bucket to a destination bucket within the same region.

  • By default, the x-oss-copy-source header in a CopyObject request specifies the current version of the object to copy. If the current version of the object is a delete marker, Object Storage Service (OSS) returns 404, which indicates that the object does not exist. You can add a version ID to x-oss-copy-source to copy the specified object version. Delete markers cannot be copied.
  • You can copy a previous version of an object to the same bucket. The copied previous version becomes the new version of the object. This way, the previous version of the object is recovered.
  • If versioning is enabled for the destination bucket, OSS generates a unique version ID for the destination object. The version ID is returned in the response as the x-oss-version-id header value. If versioning is not enabled or is suspended for the destination bucket, OSS generates a version whose version ID is null for the destination object and the generated version overwrites the original version whose version ID is null.
  • If versioning is not enabled for the destination bucket, you can copy appendable objects. If versioning is enabled or suspended for the destination bucket, you cannot copy appendable objects.
# -*- coding: utf-8 -*-
import oss2
# The AccessKey pair of an Alibaba Cloud account has permissions on all API operations. Using these credentials to perform operations in OSS is a high-risk operation. We recommend that you use a RAM user to call API operations or perform routine O&M. To create a RAM user, log on to the RAM console. 
auth = oss2.Auth('yourAccessKeyId', 'yourAccessKeySecret')
# Specify the name of the source bucket. Example: srcexamplebucket. 
src_bucket_name = 'srcexamplebucket'
# Specify the name of the destination bucket. The destination bucket must be in the same region as the source bucket. Example: destexamplebucket. 
# If you copy an object within a bucket, make sure that you specify the same bucket name for the source and destination buckets. 
dest_bucket_name = 'destexamplebucket'
# Specify the endpoint of the region in which the bucket is located. For example, if the bucket is located in the China (Hangzhou) region, set the endpoint to https://oss-cn-hangzhou.aliyuncs.com. 
bucket = oss2.Bucket(auth, 'yourEndpoint', dest_bucket_name)

# Specify the full path of the source object. Example: srcexampledir/exampleobject.txt. The full path cannot contain the bucket name. 
src_object_name = 'srcexampledir/exampleobject.txt'
# Specify the full patch of the destination object. Example: destexampledir/exampleobject.txt. The full path cannot contain the bucket name. 
# If you copy an object within a bucket, make sure that you specify the same bucket name for the source and destination buckets. 
dest_object_name = 'destexampledir/exampleobject.txt'
# Specify the version ID of the source object. 
versionId = 'CAEQMxiBgICAof2D0BYiIDJhMGE3N2M1YTI1NDQzOGY5NTkyNTI3MGYyMzJm****'

# Copy the specified version of the object. 
params = dict()
params['versionId'] = versionId

# Copy the object from the source bucket to the destination bucket. 
result = bucket.copy_object(src_bucket_name, src_object_name, dest_object_name, params=params)
# View the response. If the return value is 200, the source object is copied to the destination bucket. 
print('result.status:', result.status)

For more information about how to copy small objects, see CopyObject.

Copy a large object

To copy an object that is larger than 1 GB in size, you must split the object into parts and copy the parts by using UploadPartCopy.

By default, the UploadPartCopy operation uploads a part by copying data from the current version of an existing object. You can add versionId to the x-oss-copy-source request header to copy the specified version of the object. Example: x-oss-copy-source : /SourceBucketName/SourceObjectName?versionId=CAEQMxiBgICAof2D0BYiIDJhMGE3N2M1YTI1NDQzOGY5NTkyNTI3MGYyMzJm****.
Note The value of SourceObjectName must be URL-encoded. The version ID of the copied object is returned in the response as the value of the x-oss-copy-source-version-id header.

If versionId is not specified in the request and the current version of the source object is a delete marker, OSS returns 404 Not Found. If versionId is specified in the request and the specified version of the source object is a delete marker, OSS returns 400 Bad Request.

The following code provides an example on how to copy an object by part:
# -*- coding: utf-8 -*-
import os
import oss2
from oss2 import determine_part_size
from oss2.models import PartInfo

# The AccessKey pair of an Alibaba Cloud account has permissions on all API operations. Using these credentials to perform operations in OSS is a high-risk operation. We recommend that you use a RAM user to call API operations or perform routine O&M. To create a RAM user, log on to the RAM console. 
auth = oss2.Auth('yourAccessKeyId', 'yourAccessKeySecret')
# Specify the name of the source bucket. Example: srcexamplebucket. 
src_bucket_name = 'srcexamplebucket'
# Specify the name of the destination bucket. The destination bucket must be in the same region as the source bucket. Example: destexamplebucket. 
# If you copy an object within a bucket, make sure that you specify the same bucket name for the source and destination buckets. 
dest_bucket_name = 'destexamplebucket'
# Specify the endpoint of the region in which the bucket is located. For example, if the bucket is located in the China (Hangzhou) region, set the endpoint to https://oss-cn-hangzhou.aliyuncs.com. 
bucket = oss2.Bucket(auth, 'yourEndpoint', dest_bucket_name)
# If you copy an object within a bucket, comment out this line of code and change src_bucket in src_bucket_name to bucket. 
src_bucket = oss2.Bucket(auth, 'yourEndpoint', src_bucket_name)

# Specify the full path of the source object. Example: srcexampledir/exampleobject.txt. The full path cannot contain the bucket name. 
src_object_name = 'srcexampledir/exampleobject.txt'
# Specify the full path of the destination object. Example: destexampledir/exampleobject.txt. The full path cannot contain the bucket name. 
dest_object_name = 'destexampledir/exampleobject.txt'
# Specify the version ID of the source object. 
versionId = 'CAEQQhiBgMC5kZDE4RciIGZmNzdlYzRjYzRkODQwYjQ5ZDE0Njg5MWM0ODQzNDg3'

params = dict()
params['versionId'] = versionId

# Query the size of the specified version of the source object. If you copy an object within a bucket, change src_bucket to bucket. 
head_info = src_bucket.head_object(src_object_name, params=params)
total_size = head_info.content_length
print('src object size:', total_size)

# Use the determine_part_size method to determine the part size. 
part_size = determine_part_size(total_size, preferred_size=100 * 1024)
print('part_size:', part_size)

# Initiate a multipart upload task. 
upload_id = bucket.init_multipart_upload(dest_object_name).upload_id
parts = []

# Upload the parts one by one. 
part_number = 1
offset = 0
while offset < total_size:
    num_to_upload = min(part_size, total_size - offset)
    end = offset + num_to_upload - 1
    result = bucket.upload_part_copy(src_bucket_name, src_object_name, (offset, end), dest_object_name, upload_id, part_number, params=params)
    # Save the part information. 
    parts.append(PartInfo(part_number, result.etag))

    offset += num_to_upload
    part_number += 1

# Complete the multipart upload task. 
result = bucket.complete_multipart_upload(dest_object_name, upload_id, parts)
# Display the version ID of the destination object. 
print('result version id:', result.versionid)
# Query the metadata of the destination object. 
head_info = bucket.head_object(dest_object_name)
# Query the size of the destination object. 
dest_object_size = head_info.content_length
print('dest object size:', dest_object_size)
# Compare the sizes between the source and destination objects. 
assert dest_object_size == total_size

For more information about multipart copy, see UploadPartCopy.