全部产品
阿里云办公

上传文件

更新时间:2018-08-21 09:47:46

在OSS中,操作的基本数据单元是文件(Object)。OSS Python SDK提供了丰富的文件上传方式:

  • 简单上传:文件最大不能超过5GB。
  • 追加上传:文件最大不能超过5GB。
  • 断点续传上传:支持并发、断点续传、自定义分片大小。大文件上传推荐使用断点续传。最大不能超过48.8TB。
  • 分片上传:当文件较大时,可以使用分片上传,最大不能超过48.8TB。

说明:各种上传方式的适用场景请参见开发指南中的上传文件。

上传过程中,您还可以设置文件元信息

简单上传

简单上传的完整代码请参见GitHub

上传字符串

以下代码用于上传字符串:

  1. package main
  2. import (
  3. "fmt"
  4. "os"
  5. "strings"
  6. "github.com/aliyun/aliyun-oss-go-sdk/oss"
  7. )
  8. func main() {
  9. // 创建OSSClient实例。
  10. client, err := oss.New("<yourEndpoint>", "<yourAccessKeyId>", "<yourAccessKeySecret>")
  11. if err != nil {
  12. fmt.Println("Error:", err)
  13. os.Exit(-1)
  14. }
  15. // 获取存储空间。
  16. bucket, err := client.Bucket("<yourBucketName>")
  17. if err != nil {
  18. fmt.Println("Error:", err)
  19. os.Exit(-1)
  20. }
  21. // 上传字符串。
  22. err = bucket.PutObject("<yourObjectName>", strings.NewReader("yourObjectValue"))
  23. if err != nil {
  24. fmt.Println("Error:", err)
  25. os.Exit(-1)
  26. }
  27. }

上传Byte数组

以下代码用于上传Byte数组:

  1. package main
  2. import (
  3. "fmt"
  4. "os"
  5. "bytes"
  6. "github.com/aliyun/aliyun-oss-go-sdk/oss"
  7. )
  8. func main() {
  9. // 创建OSSClient实例。
  10. client, err := oss.New("<yourEndpoint>", "<yourAccessKeyId>", "<yourAccessKeySecret>")
  11. if err != nil {
  12. fmt.Println("Error:", err)
  13. os.Exit(-1)
  14. }
  15. // 获取存储空间。
  16. bucket, err := client.Bucket("<yourBucketName>")
  17. if err != nil {
  18. fmt.Println("Error:", err)
  19. os.Exit(-1)
  20. }
  21. // 上传Byte数组。
  22. err = bucket.PutObject("<yourObjectName>", bytes.NewReader([]byte("yourObjectValueByteArrary")))
  23. if err != nil {
  24. fmt.Println("Error:", err)
  25. os.Exit(-1)
  26. }
  27. }

上传文件流

以下代码用于上传文件流:

  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. fd, err := os.Open("<yourLocalFile>")
  22. if err != nil {
  23. fmt.Println("Error:", err)
  24. os.Exit(-1)
  25. }
  26. defer fd.Close()
  27. // 上传文件流。
  28. err = bucket.PutObject("<yourObjectName>", fd)
  29. if err != nil {
  30. fmt.Println("Error:", err)
  31. os.Exit(-1)
  32. }
  33. }

上传本地文件

以下代码用于上传本地文件:

  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. err = bucket.PutObjectFromFile("<yourObjectName>", "<yourLocalFile>")
  22. if err != nil {
  23. fmt.Println("Error:", err)
  24. os.Exit(-1)
  25. }
  26. }

追加上传

追加类型的文件(Append Object)暂时不支持copyObject操作。文件不存在时,调用AppendObject会创建一个可追加的文件;文件存在时,调用AppendObject会向文件末尾追加内容。

以下代码用于追加上传文件:

  1. package main
  2. import (
  3. "fmt"
  4. "os"
  5. "strings"
  6. "github.com/aliyun/aliyun-oss-go-sdk/oss"
  7. )
  8. func main() {
  9. // 创建OSSClient实例。
  10. client, err := oss.New("<yourEndpoint>", "<yourAccessKeyId>", "<yourAccessKeySecret>")
  11. if err != nil {
  12. fmt.Println("Error:", err)
  13. os.Exit(-1)
  14. }
  15. // 获取存储空间。
  16. bucket, err := client.Bucket("<yourBucketName>")
  17. if err != nil {
  18. fmt.Println("Error:", err)
  19. os.Exit(-1)
  20. }
  21. var nextPos int64 = 0
  22. // 第一次追加的位置是0,返回值为下一次追加的位置。后续追加的位置是追加前文件的长度。
  23. nextPos, err = bucket.AppendObject("<yourObjectName>", strings.NewReader("YourObjectAppendValue1"), nextPos)
  24. if err != nil {
  25. fmt.Println("Error:", err)
  26. os.Exit(-1)
  27. }
  28. // 第二次追加。
  29. nextPos, err = bucket.AppendObject("<yourObjectName>", strings.NewReader("YourObjectAppendValue2"), nextPos)
  30. if err != nil {
  31. fmt.Println("Error:", err)
  32. os.Exit(-1)
  33. }
  34. // 您可以进行多次Append。
  35. }

第一次追加(即开始位置是0的追加)可以指定文件元信息;后续追加不能指定文件元信息。

  1. // 第一次追加指定文件元信息。
  2. nextPos, err = bucket.AppendObject("<yourObjectName>", strings.NewReader("YourObjectValue"), 0, oss.Meta("MyProp", "MyPropVal"))
  3. if err != nil {
  4. fmt.Println("Error:", err)
  5. os.Exit(-1)
  6. }

断点续传上传

断点续传上传是指将要上传的文件分成若干个分片(Part)分别上传,所有分片都上传完成后,将所有分片合并成完整的文件,完成整个文件的上传。在上传的过程中会在Checkpoint文件中记录当前上传的进度信息,如果上传过程中某一分片上传失败,再次上传时会从Checkpoint文件中记录的点继续上传,从而达到断点续传的效果。上传完成后,Checkpoint文件会被删除。

说明:

  • SDK会将上传的中间状态信息记录在Checkpoint文件中,所以要确保程序对Checkpoint文件有写权限。Checkpoint携带了校验信息,请不要修改。如果Checkpoint文件损坏则会重新上传所有分片。
  • 如果上传过程中本地文件发生了改变,则会重新上传所有分片。

您可以使用Bucket.UploadFile实现断点续传。可设置的参数如下:

参数 说明
objectKey 上传到OSS的文件名称。
filePath 待上传的本地文件路径。
partSize 分片上传大小,取值范围为100KB~5GB。
options 可选项,包括:
- Routines:指定分片上传的并发数。默认是1,即不使用并发上传。
- Checkpoint:指定是否开启断点续传功能以及设置Checkpoint文件。默认关闭断点续传功能。例如oss.Checkpoint(true, ""), 表示开启断点续传功能,并且Checkpoint文件为与本地文件同目录下的file.cp,其中file是本地文件名称。您也可以使用oss.Checkpoint(true, "your-cp-file.cp")指定Checkpoint文件。
- 其它元信息:请参见设置文件元信息

以下代码用于断点续传上传:

  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. // 分片大小100K,3个协程并发上传分片,使用断点续传。
  21. // 其中"<yourObjectName>"为objectKey, "LocalFile"为filePath,100*1024为partSize。
  22. err = bucket.UploadFile("<yourObjectName>", "LocalFile", 100*1024, oss.Routines(3), oss.Checkpoint(true, ""))
  23. if err != nil {
  24. fmt.Println("Error:", err)
  25. os.Exit(-1)
  26. }
  27. }

分片上传

分片上传(Multipart Upload)分为以下三个步骤:

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

  2. 上传分片。
    调用Bucket.UploadPart方法上传分片数据。需要注意:

    • 对于同一个uploadId,分片号(partNumber)标识了该分片在整个文件内的相对位置。如果使用同一个分片号上传了新的数据,那么OSS上这个分片已有的数据将会被覆盖。
    • OSS将收到的分片数据的MD5值放在ETag头内返回给用户。
    • SDK自动设置Content-MD5。OSS计算上传数据的MD5值,并与SDK计算的MD5值比较,如果不一致则返回InvalidDigest错误码。
  3. 完成分片上传。
    所有分片上传完成后,调用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. // 获取存储空间。
  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. lsRes, err := bucket.ListUploadedParts(imur)
  28. if err != nil {
  29. fmt.Println("Error:", err)
  30. os.Exit(-1)
  31. }
  32. fmt.Println("Parts:", lsRes.UploadedParts)
  33. }

列举分片上传事件

您可以使用Bucket.ListMultipartUploads方法列出所有执行中的分片上传事件,即已初始化但尚未完成或已取消的分片上传事件。可设置的参数如下:

参数 说明
Delimiter 用于对Object名字进行分组的字符。所有名字包含指定的前缀且第一次出现delimiter字符之间的object作为一组元素。
MaxUploads 限定此次返回分片上传事件的最大数目,默认值和最大值均为1000。
KeyMarker 所有文件名称的字母序大于keyMarker参数值的分片上传事件。
Prefix 限定返回的文件名称必须以指定的prefix作为前缀。注意使用prefix查询时,返回的文件名称中仍会包含prefix。

使用默认参数

  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. lsRes, err := bucket.ListMultipartUploads()
  22. if err != nil {
  23. fmt.Println("Error:", err)
  24. os.Exit(-1)
  25. }
  26. fmt.Println("Uploads:", lsRes.Uploads)
  27. }

指定前缀

  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)

进度条

进度条用于指示上传或下载的进度。下面的代码以Bucket.PutObjectFromFile方法为例,介绍如何使用进度条。

  1. package main
  2. import (
  3. "fmt"
  4. "os"
  5. "github.com/aliyun/aliyun-oss-go-sdk/oss"
  6. )
  7. // 定义进度条监听器。
  8. type OssProgressListener struct {
  9. }
  10. // 定义进度变更事件处理函数。
  11. func (listener *OssProgressListener) ProgressChanged(event *oss.ProgressEvent) {
  12. switch event.EventType {
  13. case oss.TransferStartedEvent:
  14. fmt.Printf("Transfer Started, ConsumedBytes: %d, TotalBytes %d.\n",
  15. event.ConsumedBytes, event.TotalBytes)
  16. case oss.TransferDataEvent:
  17. fmt.Printf("\rTransfer Data, ConsumedBytes: %d, TotalBytes %d, %d%%.",
  18. event.ConsumedBytes, event.TotalBytes, event.ConsumedBytes*100/event.TotalBytes)
  19. case oss.TransferCompletedEvent:
  20. fmt.Printf("\nTransfer Completed, ConsumedBytes: %d, TotalBytes %d.\n",
  21. event.ConsumedBytes, event.TotalBytes)
  22. case oss.TransferFailedEvent:
  23. fmt.Printf("\nTransfer Failed, ConsumedBytes: %d, TotalBytes %d.\n",
  24. event.ConsumedBytes, event.TotalBytes)
  25. default:
  26. }
  27. }
  28. func main() {
  29. // 创建OSSClient实例。
  30. client, err := oss.New("<yourEndpoint>", "<yourAccessKeyId>", "<yourAccessKeySecret>")
  31. if err != nil {
  32. fmt.Println("Error:", err)
  33. os.Exit(-1)
  34. }
  35. bucketName := "<yourBucketName>"
  36. objectName := "<yourObjectName>"
  37. localFile := "<yourLocalFile>"
  38. // 获取存储空间。
  39. bucket, err := client.Bucket(bucketName)
  40. if err != nil {
  41. fmt.Println("Error:", err)
  42. os.Exit(-1)
  43. }
  44. // 带进度条的上传。
  45. err = bucket.PutObjectFromFile(objectName, localFile, oss.Progress(&OssProgressListener{}))
  46. if err != nil {
  47. fmt.Println("Error:", err)
  48. os.Exit(-1)
  49. }
  50. }
本文导读目录