本文介绍如何使用分片上传。
分片上传分为以下三个步骤:
初始化一个分片上传事件。
调用Bucket.InitiateMultipartUpload方法返回OSS创建的全局唯一的uploadId。上传分片。
调用Bucket.UploadPart方法上传分片数据。
注意
- 对于同一个uploadId,分片号(partNumber)标识了该分片在整个文件内的相对位置。如果使用同一个分片号上传了新的数据,那么OSS上这个分片已有的数据将会被覆盖。
- OSS将收到的分片数据的MD5值放在ETag头内返回给用户。
- SDK自动设置Content-MD5。OSS计算上传数据的MD5值,并与SDK计算的MD5值比较,如果不一致则返回InvalidDigest错误码。
- 完成分片上传。
所有分片上传完成后,调用Bucket.CompleteMultipartUpload方法将所有分片合并成完整的文件。
以下通过一个完整的示例对分片上传的流程进行逐步解析:
package main
import (
"fmt"
"os"
"github.com/aliyun/aliyun-oss-go-sdk/oss"
)
func main() {
// 创建OSSClient实例。
client, err := oss.New("<yourEndpoint>", "<yourAccessKeyId>", "<yourAccessKeySecret>")
if err != nil {
fmt.Println("Error:", err)
os.Exit(-1)
}
bucketName := "<yourBucketName>"
objectName := "<yourObjectName>"
locaFilename := "<yourLocalFilename>"
// 获取存储空间。
bucket, err := client.Bucket(bucketName)
if err != nil {
fmt.Println("Error:", err)
os.Exit(-1)
}
chunks, err := oss.SplitFileByPartNum(locaFilename, 3)
fd, err := os.Open(locaFilename)
defer fd.Close()
// 步骤1:初始化一个分片上传事件。
imur, err := bucket.InitiateMultipartUpload(objectName)
// 步骤2:上传分片。
var parts []oss.UploadPart
for _, chunk := range chunks {
fd.Seek(chunk.Offset, os.SEEK_SET)
// 对每个分片调用UploadPart方法上传。
part, err := bucket.UploadPart(imur, fd, chunk.Size, chunk.Number)
if err != nil {
fmt.Println("Error:", err)
os.Exit(-1)
}
parts = append(parts, part)
}
// 步骤3:完成分片上传。
cmur, err := bucket.CompleteMultipartUpload(imur, parts)
if err != nil {
fmt.Println("Error:", err)
os.Exit(-1)
}
fmt.Println("cmur:", cmur)
}
取消分片上传
以下代码用于取消分片上传:
package main
import (
"fmt"
"os"
"github.com/aliyun/aliyun-oss-go-sdk/oss"
)
func main() {
// 创建OSSClient实例。
client, err := oss.New("<yourEndpoint>", "<yourAccessKeyId>", "<yourAccessKeySecret>")
if err != nil {
fmt.Println("Error:", err)
os.Exit(-1)
}
// 获取存储空间。
bucket, err := client.Bucket("<yourBucketName>")
if err != nil {
fmt.Println("Error:", err)
os.Exit(-1)
}
// 初始化一个分片上传事件。
imur, err := bucket.InitiateMultipartUpload("<yourObjectName>")
if err != nil {
fmt.Println("Error:", err)
os.Exit(-1)
}
// 取消分片上传。
err = bucket.AbortMultipartUpload(imur)
if err != nil {
fmt.Println("Error:", err)
os.Exit(-1)
}
}
列举已上传的分片
以下代码用于列举某个分片上传事件中已经上传成功的分片。
package main
import (
"fmt"
"os"
"github.com/aliyun/aliyun-oss-go-sdk/oss"
)
func main() {
// 创建OSSClient实例。
client, err := oss.New("<yourEndpoint>", "<yourAccessKeyId>", "<yourAccessKeySecret>")
if err != nil {
fmt.Println("Error:", err)
os.Exit(-1)
}
bucketName := "<yourBucketName>"
objectName := "<yourObjectName>"
locaFilename := "<yourLocalFilename>"
uploadID := "<yourUploadID>"
// 获取存储空间。
bucket, err := client.Bucket(bucketName)
if err != nil {
fmt.Println("Error:", err)
os.Exit(-1)
}
// 将本地文件分片,此处分为3片。
chunks, err := oss.SplitFileByPartNum(locaFilename, 3)
fd, err := os.Open(locaFilename)
defer fd.Close()
// 初始化一个分片上传事件。
imur, err := bucket.InitiateMultipartUpload(objectName)
uploadID = imur.UploadID
fmt.Println("InitiateMultipartUpload UploadID: ", uploadID)
if err != nil {
fmt.Println("Error:", err)
os.Exit(-1)
}
// 上传分片。
var parts []oss.UploadPart
for _, chunk := range chunks {
fd.Seek(chunk.Offset, os.SEEK_SET)
// 对每个分片调用UploadPart方法上传。
part, err := bucket.UploadPart(imur, fd, chunk.Size, chunk.Number)
if err != nil {
fmt.Println("Error:", err)
os.Exit(-1)
}
fmt.Println("UploadPartNumber: ", part.PartNumber, ", ETag: ", part.ETag)
parts = append(parts, part)
}
// 根据InitiateMultipartUploadResult列举已上传的分片。
lsRes, err := bucket.ListUploadedParts(imur)
if err != nil {
fmt.Println("Error:", err)
os.Exit(-1)
}
// 打印已上传的分片。
fmt.Println("\nParts:", lsRes.UploadedParts)
for _, upload := range lsRes.UploadedParts {
fmt.Println("List PartNumber: ", upload.PartNumber, ", ETag: " ,upload.ETag, ", LastModified: ", upload.LastModified)
}
// 根据objectName和UploadID生成InitiateMultipartUploadResult,然后列举所有已上传的分片,这种情况适用于已知objectName和UploadID的情况。
var imur_with_uploadid oss.InitiateMultipartUploadResult
imur_with_uploadid.Key = objectName
imur_with_uploadid.UploadID = uploadID
// 列举已上传的分片。
lsRes, err = bucket.ListUploadedParts(imur_with_uploadid)
if err != nil {
fmt.Println("Error:", err)
os.Exit(-1)
}
// 打印已上传的分片。
fmt.Println("\nListUploadedParts by UploadID: ", uploadID)
for _, upload := range lsRes.UploadedParts {
fmt.Println("List PartNumber: ", upload.PartNumber, ", ETag: " ,upload.ETag, ", LastModified: ", upload.LastModified)
}
// 完成分片上传。
cmur, err := bucket.CompleteMultipartUpload(imur, parts)
if err != nil {
fmt.Println("Error:", err)
os.Exit(-1)
}
fmt.Println("cmur:", cmur)
}
列举分片上传事件
您可以使用Bucket.ListMultipartUploads
方法列举所有执行中的分片上传事件,即已初始化但尚未完成或已取消的分片上传事件。可设置的参数如下:
参数 | 说明 |
---|---|
Delimiter | 用于对Object名字进行分组的字符。所有名字包含指定的前缀且第一次出现delimiter字符之间的object作为一组元素。 |
MaxUploads | 限定此次返回分片上传事件的最大数目,默认值和最大值均为1000。 |
KeyMarker | 所有文件名称的字母序大于KeyMarker参数值的分片上传事件,可以与UploadIDMarker参数一同使用来指定返回结果的起始位置。 |
Prefix | 限定返回的文件名称必须以指定的prefix作为前缀。注意使用prefix查询时,返回的文件名称中仍会包含prefix。 |
UploadIDMarker | 与KeyMarker参数一同使用来指定返回结果的起始位置。 - 如果KeyMarker参数未设置,则OSS忽略该参数。 - 如果KeyMarker参数被设置,查询结果中包含: - 所有Object名字的字典序大于KeyMarker参数值的分片上传事件。 - Object名字等于KeyMarker参数值,但是Upload ID比UploadIDMarker参数值大的分片上传事件。 |
- 使用默认参数
package main
import (
"fmt"
"os"
"github.com/aliyun/aliyun-oss-go-sdk/oss"
)
func main() {
// 创建OSSClient实例。
client, err := oss.New("<yourEndpoint>", "<yourAccessKeyId>", "<yourAccessKeySecret>")
if err != nil {
fmt.Println("Error:", err)
os.Exit(-1)
}
// 获取存储空间。
bucketName := "<yourBucketName>"
bucket, err := client.Bucket(bucketName)
if err != nil {
fmt.Println("Error:", err)
os.Exit(-1)
}
// 列举所有分片上传事件。
keyMarker := ""
uploadIdMarker := ""
for {
// 默认情况下一次返回1000条记录。
lsRes, err := bucket.ListMultipartUploads(oss.KeyMarker(keyMarker), oss.UploadIDMarker(uploadIdMarker))
if err != nil {
fmt.Println("Error:", err)
os.Exit(-1)
}
// 打印分片上传事件。
for _, upload := range lsRes.Uploads {
fmt.Println("Upload: ", upload.Key, ", UploadID: ",upload.UploadID)
}
if lsRes.IsTruncated {
keyMarker = lsRes.NextKeyMarker
uploadIdMarker = lsRes.NextUploadIDMarker
} else {
break
}
}
}
- 指定前缀
lsRes, err := bucket.ListMultipartUploads(oss.Prefix("<yourObjectNamePrefix>"))
if err != nil {
fmt.Println("Error:", err)
os.Exit(-1)
}
fmt.Println("Uploads:", lsRes.Uploads)
- 指定最多返回100条结果数据
lsRes, err := bucket.ListMultipartUploads(oss.MaxUploads(100))
if err != nil {
fmt.Println("Error:", err)
os.Exit(-1)
}
fmt.Println("Uploads:", lsRes.Uploads)
- 同时指定前缀和最大返回条数
lsRes, err := bucket.ListMultipartUploads(oss.Prefix("<yourObjectNamePrefix>"), oss.MaxUploads(100))
if err != nil {
fmt.Println("Error:", err)
os.Exit(-1)
}
fmt.Println("Uploads:", lsRes.Uploads)