Copy an object (OSS SDK for Go 1.0)
This topic describes how to copy an object in a versioning-enabled bucket in Object Storage Service (OSS). You can call CopyObject to copy an object that is up to 1 GB in size and call UploadPartCopy to copy an object that is larger than 1 GB in size by using multipart copy.
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.
-
This topic demonstrates creating an OSSClient instance with an OSS endpoint. For alternative configurations, such as using a custom domain or authenticating with credentials from Security Token Service (STS), see Configure a client (Go SDK V1).
-
To copy an object, you must have the
oss:GetObjectandoss:PutObjectpermissions. For more information, see Grant a custom policy.
Sample code
Copy a small object
You can call 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.
-
If you do not specify a version ID in the x-oss-copy-source header of the CopyObject request, the current version of the object is copied. If the current version of the object is a delete marker, OSS returns HTTP status code 404. The HTTP status code indicates that the object does not exist. You can specify a version ID in the x-oss-copy-source header to copy a specific 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 current version of the object. This way, the previous version of the object is restored.
-
If versioning is enabled for the destination bucket, OSS generates a unique version ID for the destination object. The version ID is returned as the value of the x-oss-version-id header in the response. If versioning is disabled or suspended for the destination bucket, OSS generates a version whose version ID is null for the destination object and overwrites the previous version whose version ID is null.
-
Appendable objects cannot be copied to a destination bucket for which versioning is enabled or suspended.
The following sample code provides an example on 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 you run the sample code, make sure that the OSS_ACCESS_KEY_ID and OSS_ACCESS_KEY_SECRET environment variables are configured.
provider, err := oss.NewEnvironmentVariableCredentialsProvider()
if err != nil {
log.Fatalf("Failed to create credentials provider: %v", err)
}
// Create an OSSClient instance.
// 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. Specify your actual endpoint.
// Specify the region in which the bucket is located. For example, if the bucket is located in the China (Hangzhou) region, set the region to cn-hangzhou. Specify the actual region.
clientOptions := []oss.ClientOption{oss.SetCredentialsProvider(&provider)}
clientOptions = append(clientOptions, oss.Region("yourRegion"))
// Specify the version of the signature algorithm.
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)
}
// Specify the name of the bucket.
bucketName := "yourBucketName"
// Specify the full path of the source object. Do not include the bucket name in the full path.
objectName := "yourObjectName"
// Specify the full path of the destination object. Do not include the bucket name in the full path.
destObjectName := "yourDestObjectName"
// Create a bucket.
bucket, err := client.Bucket(bucketName)
if err != nil {
log.Fatalf("Failed to get bucket '%s': %v", bucketName, err)
}
// Copy the specified version of the object to the same bucket and query the version ID of the destination object.
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)
}
// Display 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
If you want to copy an object that is larger than 1 GB in size, you can call UploadPartCopy to perform multipart copy.
By default, the UploadPartCopy operation uploads a part by copying data from the current version of the specified object. You can specify a version ID in the x-oss-copy-source request header as a condition to upload a part by copying data from the specified version of an existing object. Example: x-oss-copy-source: /SourceBucketName/SourceObjectName?versionId=111111.
The value of the SourceObjectName parameter must be URL-encoded. The version ID of the copied object is returned as the value of the x-oss-copy-source-version-id header in the response.
If no version ID is specified in the request and the current version of the source object is a delete marker, OSS returns 404 Not Found. If a version ID is specified in the request and the specified version of the source object is a delete marker, OSS returns 400 Bad Request.
The following sample code provides an example on how to copy a large object by part:
package main
import (
"log"
"net/http"
"time"
"github.com/aliyun/aliyun-oss-go-sdk/oss"
)
func main() {
// Obtain access credentials from environment variables. Before you run the sample code, make sure that the OSS_ACCESS_KEY_ID and OSS_ACCESS_KEY_SECRET environment variables are configured.
provider, err := oss.NewEnvironmentVariableCredentialsProvider()
if err != nil {
log.Fatalf("Failed to create credentials provider: %v", err)
}
// Create an OSSClient instance.
// 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. Specify your actual endpoint.
// Specify the region in which the bucket is located. For example, if the bucket is located in the China (Hangzhou) region, set the region to cn-hangzhou. Specify the actual region.
clientOptions := []oss.ClientOption{oss.SetCredentialsProvider(&provider)}
clientOptions = append(clientOptions, oss.Region("yourRegion"))
// Specify the version of the signature algorithm.
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)
}
// Specify 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)
}
// Specify the full path of the object. Do not include the bucket name in the full path.
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 object as the source object.
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)
}
// Query the version ID of the source object.
versionId := oss.GetVersionId(retHeader)
log.Printf("Source object version ID: %s", versionId)
// Configure the parameters for the object copy task.
options := []oss.Option{
oss.Expires(futureDate),
oss.Meta("my", "myprop"),
}
// Specify the name of the destination object.
objectDest := objectName + "dest"
var parts []oss.UploadPart
copyOptions := []oss.Option{
oss.VersionId(versionId),
oss.GetResponseHeader(&retHeader),
}
// Initiate a multipart upload task.
imu, err := bucket.InitiateMultipartUpload(objectDest, options...)
if err != nil {
log.Fatalf("Failed to initiate multipart upload for object '%s': %v", objectDest, err)
}
// Copy the large object.
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)
// Display the value of the x-oss-copy-source-version-id header.
log.Printf("x-oss-copy-source-version-id: %s", oss.GetCopySrcVersionId(retHeader))
}
// Complete the multipart upload task.
_, err = bucket.CompleteMultipartUpload(imu, parts, oss.GetResponseHeader(&retHeader))
if err != nil {
log.Fatalf("Failed to complete multipart upload for object '%s': %v", objectDest, err)
}
// Display the value of the x-oss-version-id header.
log.Printf("x-oss-version-id: %s", oss.GetVersionId(retHeader))
}
References
-
For more information about the API operation that you can call to copy a small object, see CopyObject.
-
For more information about the API operation that you can call to copy a large object, see UploadPartCopy.