This topic describes how to copy an object in a versioning-enabled bucket. You can use the CopyObject method to copy objects smaller than 1 GB. You can use the multipart copy method (UploadPartCopy) to copy objects larger than 1 GB.
Usage notes
In this topic, the public endpoint of the China (Hangzhou) region is used. If you want to access OSS from other Alibaba Cloud services in the same region as OSS, use an internal endpoint. For more information about OSS regions and endpoints, see Regions and endpoints.
In this topic, access credentials are obtained from environment variables. For more information about how to configure access credentials, see Configure access credentials.
In this topic, an OSSClient instance is created by using an OSS endpoint. If you want to create an OSSClient instance by using custom domain names or Security Token Service (STS), see Configure OSSClient instances.
To copy an object, you must have the
oss:GetObjectandoss:PutObjectpermissions. For more information, see Attach a custom policy to a RAM user.
Sample code
Copy a small object
For objects smaller than 1 GB, you can use the CopyObject method to copy an object from a source bucket to a destination bucket in the same region.
By default, `x-oss-copy-source` copies the current version of the object. If the current version is a delete marker, OSS returns a 404 Not Found error. You can add a versionId to `x-oss-copy-source` to copy a specific version of the object. Delete markers cannot be copied.
You can copy an earlier version of an object to the same bucket. This action restores the object to its earlier state by creating a new current version of the object.
If versioning is enabled for the destination bucket, OSS automatically generates a unique versionId for the copied object. This versionId is returned in the `x-oss-version-id` response header. If versioning is not enabled or is suspended for the destination bucket, OSS generates a version with a versionId of "null" for the new object. This new version overwrites any existing version that has a versionId of "null".
You cannot copy appendable objects to a destination bucket that has versioning enabled or suspended.
The following code shows how to copy a small object:
package main
import (
"log"
"net/http"
"github.com/aliyun/aliyun-oss-go-sdk/oss"
)
func main() {
// Obtain access credentials from environment variables. Before running the sample code, make sure the OSS_ACCESS_KEY_ID and OSS_ACCESS_KEY_SECRET environment variables are set.
provider, err := oss.NewEnvironmentVariableCredentialsProvider()
if err != nil {
log.Fatalf("Failed to create credentials provider: %v", err)
}
// Create an OSSClient instance.
// Set yourEndpoint to the endpoint of the bucket. For example, for the China (Hangzhou) region, set the endpoint to https://oss-cn-hangzhou.aliyuncs.com. For other regions, use the actual endpoint.
// Set yourRegion to the region where the bucket is located. For example, for the China (Hangzhou) region, set the region to cn-hangzhou. For other regions, use the actual region.
clientOptions := []oss.ClientOption{oss.SetCredentialsProvider(&provider)}
clientOptions = append(clientOptions, oss.Region("yourRegion"))
// Set the signature version.
clientOptions = append(clientOptions, oss.AuthVersion(oss.AuthV4))
client, err := oss.New("yourEndpoint", "", "", clientOptions...)
if err != nil {
log.Fatalf("Failed to create OSS client: %v", err)
}
// Set yourBucketName to the name of the bucket.
bucketName := "yourBucketName"
// Set yourObjectName to the full path of the source object, excluding the bucket name.
objectName := "yourObjectName"
// Set yourDestObjectName to the full path of the destination object, excluding the bucket name.
destObjectName := "yourDestObjectName"
// Get the bucket instance.
bucket, err := client.Bucket(bucketName)
if err != nil {
log.Fatalf("Failed to get bucket '%s': %v", bucketName, err)
}
// Copy a specific version of an object to another object in the same bucket and get the version information.
var retHeader http.Header
_, err = bucket.CopyObject(objectName, destObjectName, oss.VersionId("yourObjectVersionId"), oss.GetResponseHeader(&retHeader))
if err != nil {
log.Fatalf("Failed to copy object '%s' to '%s': %v", objectName, destObjectName, err)
}
// Print the version information.
versionId := oss.GetVersionId(retHeader)
copySourceVersionId := oss.GetCopySrcVersionId(retHeader)
log.Printf("x-oss-version-id: %s", versionId)
log.Printf("x-oss-copy-source-version-id: %s", copySourceVersionId)
}
Copy a large object
For objects larger than 1 GB, you can use multipart copy (UploadPartCopy).
By default, the UploadPartCopy operation copies data from the current version of an existing object to upload a part. You can copy a specific version of an object by including the `versionId` subresource in the `x-oss-copy-source` request header. For example: `x-oss-copy-source: /SourceBucketName/SourceObjectName?versionId=111111`.
The `SourceObjectName` must be URL-encoded. The response returns the version ID of the source object in `x-oss-copy-source-version-id`.
If you do not specify a versionId and the current version of the object is a delete marker, OSS returns a 404 Not Found error. If you try to copy a delete marker by specifying its versionId, OSS returns a 400 Bad Request error.
The following code shows how to perform a multipart copy:
package main
import (
"log"
"net/http"
"time"
"github.com/aliyun/aliyun-oss-go-sdk/oss"
)
func main() {
// Obtain access credentials from environment variables. Before running the sample code, make sure the OSS_ACCESS_KEY_ID and OSS_ACCESS_KEY_SECRET environment variables are set.
provider, err := oss.NewEnvironmentVariableCredentialsProvider()
if err != nil {
log.Fatalf("Failed to create credentials provider: %v", err)
}
// Create an OSSClient instance.
// Set yourEndpoint to the endpoint of the bucket. For example, for the China (Hangzhou) region, set the endpoint to https://oss-cn-hangzhou.aliyuncs.com. For other regions, use the actual endpoint.
// Set yourRegion to the region where the bucket is located. For example, for the China (Hangzhou) region, set the region to cn-hangzhou. For other regions, use the actual region.
clientOptions := []oss.ClientOption{oss.SetCredentialsProvider(&provider)}
clientOptions = append(clientOptions, oss.Region("yourRegion"))
// Set the signature version.
clientOptions = append(clientOptions, oss.AuthVersion(oss.AuthV4))
client, err := oss.New("yourEndpoint", "", "", clientOptions...)
if err != nil {
log.Fatalf("Failed to create OSS client: %v", err)
}
// Set yourBucketName to the name of the bucket.
bucketName := "yourBucketName"
bucket, err := client.Bucket(bucketName)
if err != nil {
log.Fatalf("Failed to get bucket '%s': %v", bucketName, err)
}
// Set yourObjectName to the full path of the object, excluding the bucket name.
objectName := "yourObjectName"
fileName := "yourFileName"
futureDate := time.Date(2049, time.January, 10, 23, 0, 0, 0, time.UTC)
var retHeader http.Header
// Split the file.
chunks, err := oss.SplitFileByPartNum(fileName, 3)
if err != nil {
log.Fatalf("Failed to split file '%s': %v", fileName, err)
}
// Upload a large file to be copied.
err = bucket.PutObjectFromFile(objectName, fileName, oss.GetResponseHeader(&retHeader))
if err != nil {
log.Fatalf("Failed to put object '%s' from file '%s': %v", objectName, fileName, err)
}
// Get the versionId of the uploaded source file.
versionId := oss.GetVersionId(retHeader)
log.Printf("Source object version ID: %s", versionId)
// Set the parameters for the copy operation.
options := []oss.Option{
oss.Expires(futureDate),
oss.Meta("my", "myprop"),
}
// Destination object name.
objectDest := objectName + "dest"
var parts []oss.UploadPart
copyOptions := []oss.Option{
oss.VersionId(versionId),
oss.GetResponseHeader(&retHeader),
}
// Initialize a multipart upload event.
imu, err := bucket.InitiateMultipartUpload(objectDest, options...)
if err != nil {
log.Fatalf("Failed to initiate multipart upload for object '%s': %v", objectDest, err)
}
// Perform the large file copy.
for _, chunk := range chunks {
part, err := bucket.UploadPartCopy(imu, bucketName, objectName, chunk.Offset, chunk.Size, int(chunk.Number), copyOptions...)
if err != nil {
log.Fatalf("Failed to upload part %d of object '%s': %v", chunk.Number, objectName, err)
}
parts = append(parts, part)
// Print x-oss-copy-source-version-id.
log.Printf("x-oss-copy-source-version-id: %s", oss.GetCopySrcVersionId(retHeader))
}
// Complete the multipart upload.
_, err = bucket.CompleteMultipartUpload(imu, parts, oss.GetResponseHeader(&retHeader))
if err != nil {
log.Fatalf("Failed to complete multipart upload for object '%s': %v", objectDest, err)
}
// Print x-oss-version-id.
log.Printf("x-oss-version-id: %s", oss.GetVersionId(retHeader))
}
References
For more information about the API operation to copy small objects, see CopyObject.
For more information about the API operation to copy large objects, see UploadPartCopy.