1

我正在使用 Goamz 包,并且可以使用一些帮助bucket.Multi来将 HTTP GET 响应流式传输到 S3。

我将通过分块 HTTP 下载 2 GB 以上的文件,我想将它直接流式传输到 S3 存储桶中。

看来我需要resp.Body用一些东西包装一下,这样我就可以传递一个s3.ReaderAtSeekertomulti.PutAll

// set up s3
auth, _ := aws.EnvAuth()
s3Con := s3.New(auth, aws.USEast)
bucket := s3Con.Bucket("bucket-name")

// make http request to URL
resp, err := http.Get(export_url)
if err != nil {
    fmt.Printf("Get error %v\n", err)
    return
}

defer resp.Body.Close()

// set up multi-part 
multi, err := bucket.InitMulti(s3Path, "text/plain", s3.Private, s3.Options{})
if err != nil {
    fmt.Printf("InitMulti error %v\n", err)
    return
}

// Need struct that implements: s3.ReaderAtSeeker
// type ReaderAtSeeker interface {
//  io.ReaderAt
//  io.ReadSeeker
// }

rs := // Question: what can i wrap `resp.Body` in?

parts, err := multi.PutAll(rs, 5120)
if err != nil {
    fmt.Printf("PutAll error %v\n", err)
    return
}

err = multi.Complete(parts)
if err != nil {
    fmt.Printf("Complete error %v\n", err)
    return
}

目前我在尝试运行我的程序时收到以下(预期的)错误:

./main.go:50: cannot use resp.Body (type io.ReadCloser) as type s3.ReaderAtSeeker in argument to multi.PutAll:
    io.ReadCloser does not implement s3.ReaderAtSeeker (missing ReadAt method)
4

2 回答 2

1

您还没有指出您使用哪个包来访问 S3 api,但我假设它是这个 https://github.com/mitchellh/goamz/

由于您的文件很大,因此可能的解决方案是使用multi.PutPart。这将为您提供比multi.PutAll更多的控制权。使用标准库中的Reader,您的方法是:

  1. 从响应头中获取 Content-Length
  2. 根据 Content-Length 和 partSize 获取需要的零件数量
  3. 循环部分数量并将 []byte 从 response.Body 读取到 bytes.Reader 并调用 multi.PutPart
  4. multi.ListParts获取零件
  5. 调用 multi.Complete 部分。

我无权访问 S3,因此无法检验我的假设,但如果您还没有,上述内容可能值得探索。

于 2014-12-27T06:07:53.247 回答
0

一个更简单的方法是使用 - http://github.com/minio/minio-go

它实现了 PutObject(),这是一个用于上传大文件的完全托管的自包含操作。它还自动并行处理超过 5MB 的数据。如果没有指定预定义的 ContentLength。它将继续上传,直到达到 EOF。

以下示例显示了如何做到这一点,当一个没有预定义的输入长度但一个 io.Reader 正在流式传输时。在此示例中,我使用“os.Stdin”作为分块输入的等效项。

package main

import (
    "log"
    "os"

    "github.com/minio/minio-go"
)

func main() {
    config := minio.Config{
        AccessKeyID:     "YOUR-ACCESS-KEY-HERE",
        SecretAccessKey: "YOUR-PASSWORD-HERE",
        Endpoint:        "https://s3.amazonaws.com",
    }
    s3Client, err := minio.New(config)
    if err != nil {
        log.Fatalln(err)
    }

    err = s3Client.PutObject("mybucket", "myobject", "application/octet-stream", 0, os.Stdin)
    if err != nil {
        log.Fatalln(err)
    }

}
$ echo "Hello my new-object" | go run stream-object.go
于 2015-11-06T21:47:13.843 回答