This topic describes how to copy an object within a bucket or across buckets in the same region.

Usage notes

  • To copy an object, you must have read permissions on the source object and read and write permissions on the destination bucket.
  • The source bucket and the destination bucket must have no retention policies configured. Otherwise, the error message The object you specified is immutable. is returned.
  • The source bucket and the destination bucket must be in the same region. For example, objects in a bucket located in the China (Hangzhou) region cannot be copied to another bucket located in the China (Qingdao) region.

Copy a small object

You can use simple copy to copy an object whose size is smaller than 1 GB. The following code provides an example on how to use simple copy to copy an object named srcexampleobject.txt from the srcexamplebucket bucket to an object named destexampleobject.txt in the destexamplebucket bucket:

# -*- coding: utf-8 -*-
import oss2

# Security risks may arise if you use the AccessKey pair of an Alibaba Cloud account to access Object Storage Service (OSS) because the account has permissions on all API operations. We recommend that you use a RAM user to call API operations or perform routine operations and maintenance. 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, which is located 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'
# Set yourEndpoint to the endpoint of the region in which the bucket is located. For example, if the bucket is located in the China (Hangzhou) region, set yourEndpoint to https://oss-cn-hangzhou.aliyuncs.com. 
bucket = oss2.Bucket(auth, 'yourEndpoint', dest_bucket_name)

# Specify the full path of the source object. The full path of the object cannot contain the bucket name. Example: srcexampleobject.txt. 
src_object_name = 'srcexampleobject.txt'
# Specify the full path of the destination object. The full path of the object cannot contain the bucket name. Example: destexampleobject.txt. 
dest_object_name = 'destexampleobject.txt'

# headers = dict()
# Specify whether the CopyObject operation overwrites the object with the same name. In this example, this parameter is set to true, which indicates that the object with the same name cannot be overwritten. 
# headers['x-oss-forbid-overwrite'] = 'true'
# Specify the path of the source object. 
# headers[OSS_COPY_OBJECT_SOURCE] = '/example-bucket-by-util/recode-test.txt'
# If the ETag value of the source object is the same as the ETag value that is specified in the request, OSS copies the object and returns 200 OK. 
# headers['x-oss-copy-source-if-match'] = '5B3C1A2E053D763E1B002CC607C5****'
# If the ETag value of the source object is different from the ETag value that is specified in the request, OSS copies the object and returns 200 OK. 
# headers['x-oss-copy-source-if-none-match'] = '5B3C1A2E053D763E1B002CC607C5****'
# If the time that is specified in the request is equal to or later than the actual modified time of the object, OSS copies the object and returns 200 OK. 
# headers['x-oss-copy-source-if-unmodified-since'] = '2021-12-09T07:01:56.000Z'
# If the source object is modified after the time that is specified in the request, OSS copies the object. 
# headers['x-oss-copy-source-if-modified-since'] = '2021-12-09T07:01:56.000Z'
# Specify the method that is used to configure the metadata of the destination object. If you set the method to COPY, the metadata of the source object is copied to the destination object. 
# headers[OSS_METADATA_DIRECTIVE] = 'COPY'
# Specify the server-side encryption algorithm that is used to encrypt the destination object when OSS creates the destination object. 
# headers[OSS_SERVER_SIDE_ENCRYPTION] = 'KMS'
# Specify the customer master key (CMK) that is managed by Key Management Service (KMS). This parameter takes effect only when x-oss-server-side-encryption is set to KMS. 
# headers['x-oss-server-side-encryption-key-id'] = '9468da86-3509-4f8d-a61e-6eab1eac****'
# Specify the access control list (ACL) of the destination object. In this example, this parameter is set to OBJECT_ACL_PRIVATE, which indicates that only the object owner and authorized users have read and write permissions on the object. 
# headers[OSS_OBJECT_ACL] = oss2.OBJECT_ACL_PRIVATE
# Specify the storage class of the destination object. In this example, this parameter is set to BUCKET_STORAGE_CLASS_STANDARD, which indicates Standard. 
# headers['x-oss-storage-class'] = oss2.BUCKET_STORAGE_CLASS_STANDARD
# Specify the tag for the destination object. You can specify multiple tags for the destination object at the same time. 
# headers[OSS_OBJECT_TAGGING] = 'k1=v1&k2=v2&k3=v3'
# Specify the method that is used to configure the tag of the destination object. If you set the method to COPY, the tags of the source object are copied to the destination object. 
# headers[OSS_OBJECT_TAGGING_COPY_DIRECTIVE] = 'COPY'
# result = bucket.copy_object(src_bucket_name, src_object_name, dest_object_name, headers=headers)

# Copy the object from the source bucket to the destination bucket. 
result = bucket.copy_object(src_bucket_name, src_object_name, dest_object_name)

# View the HTTP status code in the returned results. If the HTTP status code 200 is returned, the execution succeeds. 
print('result.status:', result.status)

Copy a large object

To copy an object whose size is larger than 1 GB, you must split the object into parts and sequentially copy the parts by using UploadPartCopy. To implement multipart copy, perform the following steps:

  1. Use bucket.init_multipart_upload to initiate a multipart copy task.
  2. Use bucket.upload_part_copy to copy the parts. All parts must be larger than 100 KB, except for the last part.
  3. Use bucket.complete_multipart_upload to complete the multipart copy task.

The following code provides an example on how to use multipart copy to copy an object named srcexampleobject.txt from the srcexamplebucket bucket to an object named destexampleobject.txt in the destexamplebucket bucket:

# -*- coding: utf-8 -*-
import oss2
from oss2.models import PartInfo
from oss2 import determine_part_size

# Security risks may arise if you use the AccessKey pair of an Alibaba Cloud account to access OSS because the account has permissions on all API operations. We recommend that you use a RAM user to call API operations or perform routine operations and maintenance. 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, which is located 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'
# Set yourEndpoint to the endpoint of the region in which the bucket is located. For example, if the bucket is located in the China (Hangzhou) region, set yourEndpoint 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, 'https://oss-cn-hangzhou.aliyuncs.com', src_bucket_name)

# Specify the full path of the source object. The full path of the object cannot contain the bucket name. Example: srcexampleobject.txt. 
src_object_name = 'srcexampleobject.txt'
# Specify the full path of the destination object. The full path of the object cannot contain the bucket name. Example: destexampleobject.txt. 
dest_object_name = 'destexampleobject.txt'
# Obtain the size 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)
total_size = head_info.content_length
print('src object size:', total_size)

# Specify 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 copy task. 
upload_id = bucket.init_multipart_upload(dest_object_name).upload_id
parts = []

# Copy 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
    # headers = dict()
    # Specify the path of the source object.     
    # headers[OSS_COPY_OBJECT_SOURCE] = '/example-bucket-by-util/recode-test.txt'
    # Specify the range of data that you want to copy. For example, if you set bytes to 0~1023, the first 1024 bytes of the source object are copied. 
    # headers[OSS_COPY_OBJECT_SOURCE_RANGE] = 'bytes=0~1023'
    # If the ETag value of the source object is the same as the ETag value that is specified in the request, OSS copies the object and returns 200 OK. 
    # headers['x-oss-copy-source-if-match'] = '5B3C1A2E053D763E1B002CC6****'
    # If the ETag value of the source object is different from the ETag value that is specified in the request, OSS copies the object and returns 200 OK. 
    # headers['x-oss-copy-source-if-none-match'] = '5B3C1A2E053D763E1B002CC6****'
    # If the time that is specified in the request is equal to or later than the actual modified time of the object, OSS copies the object and returns 200 OK. 
    # headers['x-oss-copy-source-if-unmodified-since'] = '2021-12-09T07:01:56.000Z'
    # If the time that is specified in the request is earlier than the actual modified time of the object, OSS copies the object and returns 200 OK. 
    # headers['x-oss-copy-source-if-modified-since'] = '2021-12-09T07:01:56.000Z'  
    # result = bucket.upload_part_copy(src_bucket_name, src_object_name, (offset, end), dest_object_name, upload_id, part_number, headers=headers)
    
    result = bucket.upload_part_copy(src_bucket_name, src_object_name, (offset, end), dest_object_name, upload_id, part_number)
    # Save the part information. 
    parts.append(PartInfo(part_number, result.etag))

    offset += num_to_upload
    part_number += 1

# Complete the multipart copy task. 
result = bucket.complete_multipart_upload(dest_object_name, upload_id, parts)
# View the HTTP status code in the returned response. 
print('result :', result.status)
# 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

References

  • Copy a small object
    • For more information about the complete sample code that is used to copy a small object, visit GitHub.
    • For more information about the API operation that you can call to copy a small object, see CopyObject.
  • Copy a large object

    For more information about the API operation that you can call to copy a large object, see UploadPartCopy.