开发者社区 问答 正文

Go-SDK之如何实现上传文件?

OSS Go SDK提供了丰富的文件上传接口,用户可以通过以下方式向OSS中上传文件:

  • 简单上传PutObject,适合小文件
  • 分片上传UploadFile,适合大文件
  • 追加上传AppendObject


简单上传



从数据流(io.Reader)中读取数据上传


通过Bucket.PutObject完成简单上传。

提示:
  • 简单上传的示例代码在sample/put_object.go。


字符串上传import "strings"
    import "github.com/aliyun/aliyun-oss-go-sdk/oss"

    client, err := oss.New("Endpoint", "AccessKeyId", "AccessKeySecret")
    if err != nil {
        // HandleError(err)
    }

    bucket, err := client.Bucket("my-bucket")
    if err != nil {
        // HandleError(err)
    }

    err = bucket.PutObject("my-object", strings.NewReader("MyObjectValue"))
    if err != nil {
        // HandleError(err)
    }





byte数组上传import "bytes"
    import "github.com/aliyun/aliyun-oss-go-sdk/oss"

    client, err := oss.New("Endpoint", "AccessKeyId", "AccessKeySecret")
    if err != nil {
        // HandleError(err)
    }

    bucket, err := client.Bucket("my-bucket")
    if err != nil {
        // HandleError(err)
    }

    err = bucket.PutObject("my-object", bytes.NewReader([]byte("MyObjectValue")))
    if err != nil {
        // HandleError(err)
    }





文件流上传import "os"
    import "github.com/aliyun/aliyun-oss-go-sdk/oss"

    client, err := oss.New("Endpoint", "AccessKeyId", "AccessKeySecret")
    if err != nil {
        // HandleError(err)
    }

    bucket, err := client.Bucket("my-bucket")
    if err != nil {
        // HandleError(err)
    }

    fd, err := os.Open("LocalFile")
    if err != nil {
        // HandleError(err)
    }
    defer fd.Close()

    err = bucket.PutObject("my-object", fd)
    if err != nil {
        // HandleError(err)
    }





根据本地文件名上传


通过Bucket.PutObjectFromFile可以上传指定的本地文件,把本地文件内容作为Object的值。 import "github.com/aliyun/aliyun-oss-go-sdk/oss"

    client, err := oss.New("Endpoint", "AccessKeyId", "AccessKeySecret")
    if err != nil {
        // HandleError(err)
    }

    bucket, err := client.Bucket("my-bucket")
    if err != nil {
        // HandleError(err)
    }

    err = bucket.PutObjectFromFile("my-object", "LocalFile")
    if err != nil {
        // HandleError(err)
    }


注意:
  • 使用上述方法上传最大文件不能超过5G。如果超过请使用分片上传。


上传时指定元信息


使用数据流上传文件时,用户可以指定一个或多个文件的元信息。元数据的名称大小写不敏感,比如用户上传文件时,定义名字为“name”的meta,使用Bucket.GetObjectDetailedMeta读取结果是:“X-Oss-Meta-Name”,比较/读取时请忽略大小写。
可以指定的元信息如下:
参数说明
CacheControl指定该Object被下载时的网页的缓存行为。
ContentDisposition指定该Object被下载时的名称。
ContentEncoding指定该Object被下载时的内容编码格式。
Expires指定过期时间。用户自定义格式,建议使用http.TimeFormat格式。
ServerSideEncryption指定oss创建object时的服务器端加密编码算法。合法值:AES256。
ObjectACL指定oss创建object时的访问权限。
Meta自定义参数,以"X-Oss-Meta-"为前缀的参数。
import (
        "strings"
        "time"
        "github.com/aliyun/aliyun-oss-go-sdk/oss"
    )

    client, err := oss.New("Endpoint", "AccessKeyId", "AccessKeySecret")
    if err != nil {
        // HandleError(err)
    }

    bucket, err := client.Bucket("my-bucket")
    if err != nil {
        // HandleError(err)
    }

    expires := time.Date(2049, time.January, 10, 23, 0, 0, 0, time.UTC)
    options := []oss.Option{
        oss.Expires(expires),
        oss.ObjectACL(oss.ACLPublicRead),
        oss.Meta("MyProp", "MyPropVal"),
    }
    err = bucket.PutObject("my-object", strings.NewReader("MyObjectValue"), options...)
    if err != nil {
        // HandleError(err)
    }




提示:
  • Bucket.PutObject、Bucket.PutObjectFromFile、Bucket.UploadFile、Bucket.UploadFile都支持上传时指定元数据。


创建模拟文件夹


OSS服务是没有文件夹这个概念的,所有元素都是以文件来存储。但给用户提供了创建模拟文件夹的方式,如下代码: import "strings"
    import "github.com/aliyun/aliyun-oss-go-sdk/oss"

    client, err := oss.New("Endpoint", "AccessKeyId", "AccessKeySecret")
    if err != nil {
        // HandleError(err)
    }

    bucket, err := client.Bucket("my-bucket")
    if err != nil {
        // HandleError(err)
    }

    err = bucket.PutObject("my-dir/", strings.NewReader(""))
    if err != nil {
        // HandleError(err)
    }


提示:
  • 创建模拟文件夹本质上来说是创建了一个空文件。
  • 对于这个文件照样可以上传下载,只是控制台会对以"/"结尾的文件以文件夹的方式展示。
  • 所以用户可以使用上述方式来实现创建模拟文件夹。
  • 而对文件夹的访问可以参看文件夹功能模拟


追加上传


OSS支持可追加的文件类型,通过Bucket.AppendObject来上传可追加的文件, 调用时需要指定文件追加的位置,对于新创建文件,这个位置是0;对于已经存 在的文件,这个位置必须是追加前文件的长度。
  • 文件不存在时,调用AppendObject会创建一个可追加的文件;
  • 文件存在时,调用AppendObject会向文件末尾追加内容。

提示:
  • 追加上传的示例代码在sample/append_object.go。    import "strings"
  •     import "github.com/aliyun/aliyun-oss-go-sdk/oss"
  •     client, err := oss.New("Endpoint", "AccessKeyId", "AccessKeySecret")
  •     if err != nil {
  •         // HandleError(err)
  •     }
  •     bucket, err := client.Bucket("my-bucket")
  •     if err != nil {
  •         // HandleError(err)
  •     }
  •     var nextPos int64 = 0
  •     // 第一次追加的位置是0,返回值为下一次追加的位置
  •     nextPos, err = bucket.AppendObject("my-object", strings.NewReader("YourObjectValue"), nextPos)
  •     if err != nil {
  •         // HandleError(err)
  •     }
  •     // 第二次追加
  •     nextPos, err = bucket.AppendObject("my-object", strings.NewReader("YourObjectValue"), nextPos)
  •     if err != nil {
  •         // HandleError(err)
  •     }
  •     // 您还可以进行多次Append


注意:
  • 只能向可追加的文件(即通过AppendObject创建的文件)追加内容
  • 可追加的文件不能被拷贝

第一次追加时,即位置开始位置是0的追加,您可以指定文件(Object)的元信息;除了第一次追加,其它追加不能指定元信息。 // 第一次追加指定元信息
    nextPos, err = bucket.AppendObject("my-object", strings.NewReader("YourObjectValue"), 0, oss.Meta("MyProp", "MyPropVal"))
    if err != nil {
        // HandleError(err)
    }



分片上传


当上传大文件时,如果网络不稳定或者程序崩溃了,则整个上传就失败了。用户 不得不重头再来,这样做不仅浪费资源,在网络不稳定的情况下,往往重试多次 还是无法完成上传。 通过Bucket.UploadFile接口来实现断点续传上传。它有以下参数:
  • objectKey 上传到OSS的Object名字
  • filePath 待上传的本地文件路径
  • partSize 分片上传大小,从100KB到5GB,单位是Byte
  • options 可选项,主要包括:Routines 指定分片上传的并发数,默认是1,及不使用并发上传
  • Checkpoint 指定上传是否开启断点续传,及checkpoint文件的路径。默认断点续传功能关闭,checkpoint文件的路径可以指定为空,为与本地文件同 目录下的file.cp,其中file是本地文件的名字
  • 其它元信息,请参看上传时指定元信息

其实现的原理是将要上传的文件分成若干个分片分别上传,最后所有分片都上传 成功后,完成整个文件的上传。在上传的过程中会记录当前上传的进度信息(记 录在checkpoint文件中),如果上传过程中某一分片上传失败,再次上传时会从 checkpoint文件中记录的点继续上传。这要求再次调用时要指定与上次相同的 checkpoint文件。上传完成后,checkpoint文件会被删除。

提示:
  • 分片上传的示例代码在sample/put_object.go。    import "github.com/aliyun/aliyun-oss-go-sdk/oss"
  •     client, err := oss.New("Endpoint", "AccessKeyId", "AccessKeySecret")
  •     if err != nil {
  •         // HandleError(err)
  •     }
  •     bucket, err := client.Bucket("my-bucket")
  •     if err != nil {
  •         // HandleError(err)
  •     }
  •     // 分片大小100K,3个协程并发上传分片,使用断点续传
  •     err = bucket.UploadFile("my-object", "LocalFile", 100*1024, oss.Routines(3), oss.Checkpoint(true, ""))
  •     if err != nil {
  •         // HandleError(err)
  •     }


注意:
  • SDK会将上传的中间状态信息记录在cp文件中,所以要确保用户对cp文件有写权限
  • cpt文件记录了上传的中间状态信息并自带了校验,用户不能去编辑它,如 果cpt文件损坏则重新上传所有分片。整个上传完成后cpt文件会被删除。
  • 如果上传过程中本地文件发生了改变,则重新上传所有分片

提示:
  • 指定断点续传checkpoint文件路径使用oss.Checkpoint(true, "your-cp-file.cp")
  • 使用bucket.UploadFile(objectKey, localFile, 100*1024),默认不使用分片并发上传、不启动断点续传


获取所有已上传的分片信息


您可以用Bucket.ListUploadedParts获取某个分片上传已上传的分片。 import "fmt"
    import "github.com/aliyun/aliyun-oss-go-sdk/oss"

    client, err := oss.New("Endpoint", "AccessKeyId", "AccessKeySecret")
    if err != nil {
        // HandleError(err)
    }

    bucket, err := client.Bucket("my-bucket")
    if err != nil {
        // HandleError(err)
    }

    imur, err := bucket.InitiateMultipartUpload("my-object")
    if err != nil {
        // HandleError(err)
    }

    lsRes, err := bucket.ListUploadedParts(imur)
    if err != nil {
        // HandleError(err)
    }
    fmt.Println("Parts:", lsRes.UploadedParts)



获取所有分片上传的任务


通过Bucket.ListMultipartUploads来列出当前分片上传任务。主要的参数如下:
参数说明
Delimiter用于对Object名字进行分组的字符。所有名字包含指定的前缀且第一次出现delimiter字符之间的object作为一组元素。
MaxUploads限定此次返回Multipart Uploads事件的最大数目,默认为1000,max-uploads取值不能大于1000。
KeyMarker所有Object名字的字典序大于KeyMarker参数值的Multipart事件。
Prefix限定返回的文件名(object)必须以Prefix作为前缀。注意使用Prefix查询时,返回的文件名(Object)中仍会包含Prefix。


使用默认参数import "fmt"
    import "github.com/aliyun/aliyun-oss-go-sdk/oss"

    client, err := oss.New("Endpoint", "AccessKeyId", "AccessKeySecret")
    if err != nil {
        // HandleError(err)
    }

    bucket, err := client.Bucket("my-bucket")
    if err != nil {
        // HandleError(err)
    }

    lsRes, err := bucket.ListMultipartUploads()
    if err != nil {
        // HandleError(err)
    }
    fmt.Println("Uploads:", lsRes.Uploads)





指定前缀lsRes, err := bucket.ListMultipartUploads(oss.Prefix("my-object-"))
    if err != nil {
        // HandleError(err)
    }
    fmt.Println("Uploads:", lsRes.Uploads)





指定最多返回100条结果数据lsRes, err := bucket.ListMultipartUploads(oss.MaxUploads(100))
    if err != nil {
        // HandleError(err)
    }
    fmt.Println("Uploads:", lsRes.Uploads)





同时指定前缀和最大返回条数lsRes, err := bucket.ListMultipartUploads(oss.Prefix("my-object-"), oss.MaxUploads(100))
    if err != nil {
        // HandleError(err)
    }
    fmt.Println("Uploads:", lsRes.Uploads)



展开
收起
青衫无名 2017-10-19 14:22:58 7116 分享 版权
0 条回答
写回答
取消 提交回答