本文介绍如何使用分片上传。

分片上传分为以下三个步骤:

  • 初始化一个分片上传事件。
    调用Bucket.InitiateMultipartUpload方法返回OSS创建的全局唯一的uploadId。

  • 上传分片。
    调用Bucket.UploadPart方法上传分片数据。

注意

  • 对于同一个uploadId,分片号(partNumber)标识了该分片在整个文件内的相对位置。如果使用同一个分片号上传了新的数据,那么OSS上这个分片已有的数据将会被覆盖。
  • OSS将收到的分片数据的MD5值放在ETag头内返回给用户。
  • SDK自动设置Content-MD5。OSS计算上传数据的MD5值,并与SDK计算的MD5值比较,如果不一致则返回InvalidDigest错误码。
  • 完成分片上传。
    所有分片上传完成后,调用Bucket.CompleteMultipartUpload方法将所有分片合并成完整的文件。

以下通过一个完整的示例对分片上传的流程进行逐步解析:

  1. package main
  2. import (
  3. "fmt"
  4. "os"
  5. "github.com/aliyun/aliyun-oss-go-sdk/oss"
  6. )
  7. func main() {
  8. // 创建OSSClient实例。
  9. client, err := oss.New("<yourEndpoint>", "<yourAccessKeyId>", "<yourAccessKeySecret>")
  10. if err != nil {
  11. fmt.Println("Error:", err)
  12. os.Exit(-1)
  13. }
  14. bucketName := "<yourBucketName>"
  15. objectName := "<yourObjectName>"
  16. locaFilename := "<yourLocalFilename>"
  17. // 获取存储空间。
  18. bucket, err := client.Bucket(bucketName)
  19. if err != nil {
  20. fmt.Println("Error:", err)
  21. os.Exit(-1)
  22. }
  23. chunks, err := oss.SplitFileByPartNum(locaFilename, 3)
  24. fd, err := os.Open(locaFilename)
  25. defer fd.Close()
  26. // 步骤1:初始化一个分片上传事件。
  27. imur, err := bucket.InitiateMultipartUpload(objectName)
  28. // 步骤2:上传分片。
  29. var parts []oss.UploadPart
  30. for _, chunk := range chunks {
  31. fd.Seek(chunk.Offset, os.SEEK_SET)
  32. // 对每个分片调用UploadPart方法上传。
  33. part, err := bucket.UploadPart(imur, fd, chunk.Size, chunk.Number)
  34. if err != nil {
  35. fmt.Println("Error:", err)
  36. os.Exit(-1)
  37. }
  38. parts = append(parts, part)
  39. }
  40. // 步骤3:完成分片上传。
  41. cmur, err := bucket.CompleteMultipartUpload(imur, parts)
  42. if err != nil {
  43. fmt.Println("Error:", err)
  44. os.Exit(-1)
  45. }
  46. fmt.Println("cmur:", cmur)
  47. }

取消分片上传

以下代码用于取消分片上传:

  1. package main
  2. import (
  3. "fmt"
  4. "os"
  5. "github.com/aliyun/aliyun-oss-go-sdk/oss"
  6. )
  7. func main() {
  8. // 创建OSSClient实例。
  9. client, err := oss.New("<yourEndpoint>", "<yourAccessKeyId>", "<yourAccessKeySecret>")
  10. if err != nil {
  11. fmt.Println("Error:", err)
  12. os.Exit(-1)
  13. }
  14. // 获取存储空间。
  15. bucket, err := client.Bucket("<yourBucketName>")
  16. if err != nil {
  17. fmt.Println("Error:", err)
  18. os.Exit(-1)
  19. }
  20. // 初始化一个分片上传事件。
  21. imur, err := bucket.InitiateMultipartUpload("<yourObjectName>")
  22. if err != nil {
  23. fmt.Println("Error:", err)
  24. os.Exit(-1)
  25. }
  26. // 取消分片上传。
  27. err = bucket.AbortMultipartUpload(imur)
  28. if err != nil {
  29. fmt.Println("Error:", err)
  30. os.Exit(-1)
  31. }
  32. }

列举已上传的分片

以下代码用于列举某个分片上传事件中已经上传成功的分片。

  1. package main
  2. import (
  3. "fmt"
  4. "os"
  5. "github.com/aliyun/aliyun-oss-go-sdk/oss"
  6. )
  7. func main() {
  8. // 创建OSSClient实例。
  9. client, err := oss.New("<yourEndpoint>", "<yourAccessKeyId>", "<yourAccessKeySecret>")
  10. if err != nil {
  11. fmt.Println("Error:", err)
  12. os.Exit(-1)
  13. }
  14. bucketName := "<yourBucketName>"
  15. objectName := "<yourObjectName>"
  16. locaFilename := "<yourLocalFilename>"
  17. uploadID := "<yourUploadID>"
  18. // 获取存储空间。
  19. bucket, err := client.Bucket(bucketName)
  20. if err != nil {
  21. fmt.Println("Error:", err)
  22. os.Exit(-1)
  23. }
  24. // 将本地文件分片,此处分为3片。
  25. chunks, err := oss.SplitFileByPartNum(locaFilename, 3)
  26. fd, err := os.Open(locaFilename)
  27. defer fd.Close()
  28. // 初始化一个分片上传事件。
  29. imur, err := bucket.InitiateMultipartUpload(objectName)
  30. uploadID = imur.UploadID
  31. fmt.Println("InitiateMultipartUpload UploadID: ", uploadID)
  32. if err != nil {
  33. fmt.Println("Error:", err)
  34. os.Exit(-1)
  35. }
  36. // 上传分片。
  37. var parts []oss.UploadPart
  38. for _, chunk := range chunks {
  39. fd.Seek(chunk.Offset, os.SEEK_SET)
  40. // 对每个分片调用UploadPart方法上传。
  41. part, err := bucket.UploadPart(imur, fd, chunk.Size, chunk.Number)
  42. if err != nil {
  43. fmt.Println("Error:", err)
  44. os.Exit(-1)
  45. }
  46. fmt.Println("UploadPartNumber: ", part.PartNumber, ", ETag: ", part.ETag)
  47. parts = append(parts, part)
  48. }
  49. // 根据InitiateMultipartUploadResult列举已上传的分片。
  50. lsRes, err := bucket.ListUploadedParts(imur)
  51. if err != nil {
  52. fmt.Println("Error:", err)
  53. os.Exit(-1)
  54. }
  55. // 打印已上传的分片。
  56. fmt.Println("\nParts:", lsRes.UploadedParts)
  57. for _, upload := range lsRes.UploadedParts {
  58. fmt.Println("List PartNumber: ", upload.PartNumber, ", ETag: " ,upload.ETag, ", LastModified: ", upload.LastModified)
  59. }
  60. // 根据objectName和UploadID生成InitiateMultipartUploadResult,然后列举所有已上传的分片,这种情况适用于已知objectName和UploadID的情况。
  61. var imur_with_uploadid oss.InitiateMultipartUploadResult
  62. imur_with_uploadid.Key = objectName
  63. imur_with_uploadid.UploadID = uploadID
  64. // 列举已上传的分片。
  65. lsRes, err = bucket.ListUploadedParts(imur_with_uploadid)
  66. if err != nil {
  67. fmt.Println("Error:", err)
  68. os.Exit(-1)
  69. }
  70. // 打印已上传的分片。
  71. fmt.Println("\nListUploadedParts by UploadID: ", uploadID)
  72. for _, upload := range lsRes.UploadedParts {
  73. fmt.Println("List PartNumber: ", upload.PartNumber, ", ETag: " ,upload.ETag, ", LastModified: ", upload.LastModified)
  74. }
  75. // 完成分片上传。
  76. cmur, err := bucket.CompleteMultipartUpload(imur, parts)
  77. if err != nil {
  78. fmt.Println("Error:", err)
  79. os.Exit(-1)
  80. }
  81. fmt.Println("cmur:", cmur)
  82. }

列举分片上传事件

您可以使用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参数值大的分片上传事件。
  • 使用默认参数
  1. package main
  2. import (
  3. "fmt"
  4. "os"
  5. "github.com/aliyun/aliyun-oss-go-sdk/oss"
  6. )
  7. func main() {
  8. // 创建OSSClient实例。
  9. client, err := oss.New("<yourEndpoint>", "<yourAccessKeyId>", "<yourAccessKeySecret>")
  10. if err != nil {
  11. fmt.Println("Error:", err)
  12. os.Exit(-1)
  13. }
  14. // 获取存储空间。
  15. bucketName := "<yourBucketName>"
  16. bucket, err := client.Bucket(bucketName)
  17. if err != nil {
  18. fmt.Println("Error:", err)
  19. os.Exit(-1)
  20. }
  21. // 列举所有分片上传事件。
  22. keyMarker := ""
  23. uploadIdMarker := ""
  24. for {
  25. // 默认情况下一次返回1000条记录。
  26. lsRes, err := bucket.ListMultipartUploads(oss.KeyMarker(keyMarker), oss.UploadIDMarker(uploadIdMarker))
  27. if err != nil {
  28. fmt.Println("Error:", err)
  29. os.Exit(-1)
  30. }
  31. // 打印分片上传事件。
  32. for _, upload := range lsRes.Uploads {
  33. fmt.Println("Upload: ", upload.Key, ", UploadID: ",upload.UploadID)
  34. }
  35. if lsRes.IsTruncated {
  36. keyMarker = lsRes.NextKeyMarker
  37. uploadIdMarker = lsRes.NextUploadIDMarker
  38. } else {
  39. break
  40. }
  41. }
  42. }
  • 指定前缀
  1. lsRes, err := bucket.ListMultipartUploads(oss.Prefix("<yourObjectNamePrefix>"))
  2. if err != nil {
  3. fmt.Println("Error:", err)
  4. os.Exit(-1)
  5. }
  6. fmt.Println("Uploads:", lsRes.Uploads)
  • 指定最多返回100条结果数据
  1. lsRes, err := bucket.ListMultipartUploads(oss.MaxUploads(100))
  2. if err != nil {
  3. fmt.Println("Error:", err)
  4. os.Exit(-1)
  5. }
  6. fmt.Println("Uploads:", lsRes.Uploads)
  • 同时指定前缀和最大返回条数
  1. lsRes, err := bucket.ListMultipartUploads(oss.Prefix("<yourObjectNamePrefix>"), oss.MaxUploads(100))
  2. if err != nil {
  3. fmt.Println("Error:", err)
  4. os.Exit(-1)
  5. }
  6. fmt.Println("Uploads:", lsRes.Uploads)