This topic describes how to copy objects in a bucket with versioning enabled or suspended.

Copy small objects

You can use the CopyObject method to copy an object smaller than 1 GB from a bucket (source bucket) to another bucket (target bucket) in the same region.

Note
  • CopyObject copies the current version of an object by default. If the current version of the target object is a delete marker, the 404 Not Found error is returned to indicate that the object does not exist. You can specify the versionId in a CopyObject request to copy a specified version of the target object. However, a delete marker cannot be copied
  • You can copy a historical version of an object to the bucket that stores the object. The copied historical version becomes the current version of a new object. You can use this method to restore a historical version of an object.
  • If versioning is enabled for the bucket that stores the target object, OSS generates a unique version ID for the copied object, which is returned in the x-oss-version-id field in the response header. If versioning is suspended or not enabled for the bucket that stores the target object, OSS generates a version of which the ID is null for the copied object and overwrite overwrites the original version of which the ID is null.
You can run the following code to copy objects smaller than 1 GB:
# -*- coding: utf-8 -*-
import oss2

# It is highly risky to log on with the AccessKey of an Alibaba Cloud account because the account has permissions on all the APIs in OSS. We recommend that you log on as a RAM user to access APIs or perform routine operations and maintenance. To create a RAM user account, log on to https://ram.console.aliyun.com.
auth = oss2.Auth('<yourAccessKeyId>', '<yourAccessKeySecret>')
# This example uses the China East 1 (Hangzhou) endpoint. Specify the actual endpoint based on your requirements.
bucket = oss2.Bucket(auth, 'http://oss-cn-hangzhou.aliyuncs.com', '<yourBucketName>')

# Copies a specified version of the object.
params = dict()
params['versionId'] = '<yourObjectVersionId>'
result = bucket.copy_object('<yourBucketName>',  '<yourSourceObjectName>', '<yourDestinationObjectName>', params=params)
# Views the version ID of the object in the target bucket.
print('result.versionid:', result.versionid)

For more information about copying objects smaller than 1 GB, see CopyObject.

Copy large objects

To copy an object larger than 1 GB, you must use UploadPartCopy.

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

If you do not specify the versionId in the request header and the current version of the object to be copied is a delete marker, the 404 Not Found error is returned. If you specify the versionId in the request header and the specified version of the object is a delete marker, the 400 Bad Request error is returned.

You can run the following code to copy an object by using UploadPartCopy:
# -*- coding: utf-8 -*-
import os
import oss2
from oss2 import determine_part_size
from oss2.models import PartInfo

# It is highly risky to log on with the AccessKey of an Alibaba Cloud account because the account has permissions on all the APIs in OSS. We recommend that you log on as a RAM user to access APIs or perform routine operations and maintenance. To create a RAM user account, log on to https://ram.console.aliyun.com.
auth = oss2.Auth('<yourAccessKeyId>', '<yourAccessKeySecret>')
# This example uses the China East 1 (Hangzhou) endpoint. Specify the actual endpoint based on your requirements.
bucket = oss2.Bucket(auth, 'http://oss-cn-hangzhou.aliyuncs.com', '<yourBucketName>')

src_object_name = '<yourSrcObject>'
dest_object_name = '<yourDestObject>'

params = dict()
params['versionId'] = '<yourObjectVersionId>'

# Obtains the size of a specified version of the source object.
head_info = bucket.head_object(src_object_name, params=params)
total_size = head_info.content_length
print('src object size:', total_size)

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

# Initializes the parts.
upload_id = bucket.init_multipart_upload(dest_object_name).upload_id
parts = []

# Uploads 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(bucket.bucket_name, src_object_name, (offset, end), dest_object_name, upload_id, part_number, params=params)
    # Saves the part information.
    parts.append(PartInfo(part_number, result.etag))

    offset += num_to_upload
    part_number += 1

# Completes the UploadPartCopy task.
result = bucket.complete_multipart_upload(dest_object_name, upload_id, parts)
# Views the version ID of the target object.
print('result version id:', result.versionid)
# Obtains the metadata of the target object.
head_info = bucket.head_object(dest_object_name)
# Views the size of the target object.
dest_object_size = head_info.content_length
print('dest object size:', dest_object_size)
# Compares the size of the target object with that of the source object.
assert dest_object_size == total_size

For more information about UploadPartCopy, see UploadPartCopy.