复制对象
CopyObject操作用于创建一个已经在媒体存储中的对象。使用CopyOoject可以拷贝单个最大为5GB的对象,如果需要拷贝更大的对象,可以使用UploadPartCopy操作。执行CopyObject操作,必须具有对被拷贝对象的READ权限和对目标bucket的WRITE权限。
拷贝生成的对象默认保留原对象的元数据信息,也可以才CopyObject操作中指定新的元数据。拷贝生成的对象不会保留原来的ACL信息,该对象默认是发起CopyObject操作的用户私有的。
CopyObject操作默认拷贝原对象的当前版本数据,如果需要拷贝原对象的指定版本,可以在CopySource中加入versionId来拷贝指定的Object版本,如果原对象的versionId为删除标记,则不会被拷贝。如果目标bucket开启了版本控制,那么拷贝生成的对象会有一个与原对象不同的唯一的versionId,并且会在响应头部字段 x-amz-version-id中返回该versionId。
代码示例:
// 拷贝对象
func CopyObject(svc *s3.S3) {
copyObjectInput := &s3.CopyObjectInput{
Bucket: aws.String("destinationBucket"),
CopySource: aws.String("exampleBucket/exampleKey"),
Key: aws.String("copiedObjectKey"),
}
copyObjectOutput, err := svc.CopyObject(copyObjectInput)
if err != nil {
fmt.Printf("fail to copy object. %v\n", err)
}
fmt.Println(copyObjectOutput)
}
CopyObjectInput可设置的参数如下:
参数 | 类型 | 说明 | 是否必要 |
---|---|---|---|
ACL | *string | 拷贝后对象的预定义的标准ACL信息,例如private,public-read,public-read-write等。 | 否 |
Bucket | *string | 存放拷贝生成对象的桶名称。 | 是 |
CopySource | *string | URL格式的拷贝对象数据来源,包含了桶名称和对象key的信息,二者之间使用正斜杆(/)分割,versionId可选参数用于指定原对象的版本。例如,“foo/boo?versionId=11111"表示拷贝foo桶中的boo对象,其版本id为11111。如果不指定versionId参数,则默认拷贝当前版本的对象数据。 | 是 |
Key | *string | 拷贝生成对象对应的key。 | 是 |
Metadata | map[string]*string | 拷贝生成对象的元数据信息。 | 否 |
Tagging | *string | 拷贝生成对象的标签信息,必须是URL请求参数的形式。例如,“Key1=Value1”。 | 否 |
CopyObjectOutput返回的属性如下:
参数 | 类型 | 说明 |
---|---|---|
CopyObjectResult | *CopyObjectResult | 包含拷贝生成对象的Entity Tag和最后修改时间等信息。 |
RequestCharged | *string | 如果返回结果中包含该属性,表示请求的发起者对该次请求操作付费。 |
响应结果:
HTTP状态 | 响应码 | 描述 |
---|---|---|
200 | Success | 操作成功。 |
400 | EntityTooLarge | 拷贝的对象太大。 |
400 | InvalidObjectName | 对象的名字不合法 |
403 | AccessDenied | 用户没有权限执行操作。 |
404 | NoSuchKey | 请求参数中CopySource对应的对象不存在。 |
文件比较大(超过1GB)的情况下,直接使用copyObject 可能会出现超时,需要使用分片复制的方式进行文件复制。
代码示例:
const max_part_size = 5 * 1024 * 1024
func (p *S3Demo) buildCopySourceRange(start int64, objectSize int64) string {
end := start + max_part_size - 1
if end > objectSize {
end = objectSize - 1
}
startRange := strconv.FormatInt(start, 10)
stopRange := strconv.FormatInt(end, 10)
return "bytes=" + startRange + "-" + stopRange
}
func (p *S3Demo) multiPartCopy() {
sourceBucket := S3Bucket
sourceKey := "2.avi"
destBucket := S3Bucket
destKey := "3.avi"
headOut, err := p.svc.HeadObject(&s3.HeadObjectInput{
Bucket: aws.String(sourceBucket),
Key: aws.String(sourceKey),
})
if err != nil {
log.Printf("err, %s\n", err)
return
}
fileSize := *headOut.ContentLength
//send command to start copy and get the upload id as it is needed later
createOutput, err := p.svc.CreateMultipartUpload(&s3.CreateMultipartUploadInput{
Bucket: &destBucket,
Key: &destKey,
})
if err != nil {
log.Printf("err, %s\n", err)
return
}
uploadId := *createOutput.UploadId
partNumber := int64(1)
copySource := "/" + sourceBucket + "/" + sourceKey
parts := make([]*s3.CompletedPart, 0)
numUploads := fileSize / max_part_size
log.Printf("Will attempt upload in %d number of parts to %s\n", numUploads, destKey)
for i := int64(0); i < fileSize; i += max_part_size {
copyRange := p.buildCopySourceRange(i, fileSize)
partInput := s3.UploadPartCopyInput{
Bucket: &destBucket,
CopySource: ©Source,
CopySourceRange: ©Range,
Key: &destKey,
PartNumber: &partNumber,
UploadId: &uploadId,
}
log.Printf("Attempting to upload part %d range: %s\n", partNumber, copyRange)
partResp, err := p.svc.UploadPartCopy(&partInput)
if err != nil {
log.Printf("Error uploading part %d : %s\n", partNumber, err)
log.Printf("Attempting to abort upload\n")
//ignoring any errors with aborting the copy
p.svc.AbortMultipartUploadRequest(&s3.AbortMultipartUploadInput{
UploadId: &uploadId,
})
return
}
//copy etag and part number from response as it is needed for completion
if partResp != nil {
partNum := partNumber
etag := strings.Trim(*partResp.CopyPartResult.ETag, "\"")
cPart := s3.CompletedPart{
ETag: &etag,
PartNumber: &partNum,
}
parts = append(parts, &cPart)
log.Printf("Successfully upload part %d of %s\n", partNumber, uploadId)
}
partNumber++
if partNumber%50 == 0 {
log.Printf("Completed part %d of %d to %s\n", partNumber, numUploads, destKey)
}
}
// complete
complete := s3.CompleteMultipartUploadInput{
Bucket: &destBucket,
Key: &destKey,
UploadId: &uploadId,
MultipartUpload: &s3.CompletedMultipartUpload{
Parts: parts,
},
}
compOutput, err := p.svc.CompleteMultipartUpload(&complete)
if err != nil {
log.Printf("Error completing upload: %s\n", err)
return
}
if compOutput != nil {
log.Printf("Successfully copied Bucket: %s Key: %s to Bucket: %s Key: %s\n",
sourceBucket, sourceKey, destBucket, destKey)
}
}