为了账号安全,请及时绑定邮箱和手机立即绑定

如何从 io.ReadCloser 转到 io.ReadSeeker?

如何从 io.ReadCloser 转到 io.ReadSeeker?

Go
哔哔one 2022-01-17 16:52:03
我正在尝试从 S3 下载文件并将该文件上传到 S3 中的另一个存储桶。Copy API 在这里不起作用,因为我被告知不要使用它。从 S3 获取对象有一个response.Bodythat's anio.ReadCloser并且要上传该文件,有效负载需要一个Bodythat's an io.ReadSeeker.我能解决这个问题的唯一方法是将 保存response.Body到文件中,然后将该文件作为io.ReadSeeker. 这需要先将整个文件写入磁盘,然后从磁盘读取整个文件,这听起来很错误。我想做的是:resp, _ := conn.GetObject(&s3.GetObjectInput{Key: "bla"})conn.PutObject(&s3.PutObjectInput{Body: resp.Body}) // resp.Body is an io.ReadCloser and the field type expects an io.ReadSeeker问题是,我如何以最有效的方式从一个io.ReadCloser到一个?io.ReadSeeker
查看完整描述

2 回答

?
肥皂起泡泡

TA贡献1829条经验 获得超6个赞

io.ReadSeeker是分组基本Read()Seek()方法的接口。方法的定义Seek()

Seek(offset int64, whence int) (int64, error)

Seek()方法的实现需要能够在源中的任何位置寻找,这要求所有源都可用或可重现。文件就是一个很好的例子,该文件永久保存到您的磁盘中,并且可以随时读取其中的任何部分。

response.Body被实现为从底层 TCP 连接中读取。从底层 TCP 连接中读取数据会为您提供另一端的客户端发送给您的数据。数据不会被缓存,客户端不会根据请求再次向您发送数据。这就是为什么response.Body不实施io.Seeker(因此也不实施io.ReadSeeker)。

因此,为了io.ReadSeekerio.Readeror中获取 an io.ReadCloser,您需要缓存所有数据的东西,以便根据请求它可以搜索到其中的任何位置。

正如您提到的,这种缓存机制可能会将其写入文件,或者您可以将所有内容读入内存,读入[]byteusing ioutil.ReadAll(),然后您可以使用bytes.NewReader()从. 当然,这有其局限性:所有内容都必须适合内存,而且您可能不想为此文件复制操作保留该内存量。io.ReadSeeker[]byte

总而言之,实现io.Seekerio.ReadSeeker要求所有源数据都可用,因此最好的选择是将其写入文件,或者将小文件全部读入 a[]byte并流式传输该字节片的内容。


查看完整回答
反对 回复 2022-01-17
?
ibeautiful

TA贡献1993条经验 获得超6个赞

作为替代方案,使用github.com/aws/aws-sdk-go/service/s3/s3manager.Uploader,它将 aio.Reader作为输入。

我想PutObject采用 anio.ReadSeeker而不是 an的原因io.Reader是对 s3 的请求需要签名(并且具有内容长度),但是在拥有所有数据之前您无法生成签名。执行此操作的流式方法是将输入缓冲到块中,并使用分段上传 api 分别上传每个块。这是(我认为)s3manager.Uploader在幕后所做的。


查看完整回答
反对 回复 2022-01-17
  • 2 回答
  • 0 关注
  • 518 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号