Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/go/7.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Go 如何从io.ReadCloser到io.ReadSeek?_Go - Fatal编程技术网

Go 如何从io.ReadCloser到io.ReadSeek?

Go 如何从io.ReadCloser到io.ReadSeek?,go,Go,我正在尝试从S3下载一个文件,并将该文件上传到S3中的另一个bucket中。复制API在这里不起作用,因为我被告知不要使用它 从S3获取对象有一个响应。Body这是一个io.ReadCloser,要上载该文件,有效负载需要一个Body这是一个io.ReadSeeker 我能找出这个问题的唯一方法是将response.Body保存到一个文件中,然后将该文件作为io.readseek传递。这需要先将整个文件写入磁盘,然后从磁盘读取整个文件,这听起来非常错误 我想做的是: resp, _ := con

我正在尝试从S3下载一个文件,并将该文件上传到S3中的另一个bucket中。复制API在这里不起作用,因为我被告知不要使用它

从S3获取对象有一个
响应。Body
这是一个
io.ReadCloser
,要上载该文件,有效负载需要一个
Body
这是一个
io.ReadSeeker

我能找出这个问题的唯一方法是将
response.Body
保存到一个文件中,然后将该文件作为
io.readseek
传递。这需要先将整个文件写入磁盘,然后从磁盘读取整个文件,这听起来非常错误

我想做的是:

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.readseek

是对基本
Read()
Seek()方法进行分组的接口。
Seek()
方法的定义:

Seek(offset int64, whence int) (int64, error)
Seek()
方法的实现要求能够搜索源中的任何位置,这要求所有源都可用或可复制。一个文件就是一个完美的例子,该文件被永久保存到您的磁盘上,并且可以随时读取其中的任何部分

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

因此,为了从
io.ReadSeeker
io.ReadCloser
获取
io.ReadSeeker
,您需要一种缓存所有数据的东西,以便在请求时它可以搜索到其中的任何位置

此缓存机制可能正在将其写入您提到的文件,或者您可以使用将所有内容读入内存,读入
[]字节
,然后您可以使用从
[]字节
获取
io.ReadSeeker
。当然,这也有其局限性:所有内容都必须放入内存中,而且您可能不想为该文件复制操作保留足够的内存

总之,
io.Seeker
io.ReadSeeker
的实现要求所有源数据都可用,因此最好将其写入文件,或者对于小文件,将其全部读取到
[]字节中,并将该字节片的内容流式传输。

作为替代方法,使用,它将
io.Reader
作为输入


我想
PutObject
采用
io.ReadSeeker
而不是
io.Reader
的原因是,对s3的请求需要签名(并且具有内容长度),但在获得所有数据之前,无法生成签名。stream-y实现这一点的方法是将输入缓冲到块中,然后使用多部分上传api分别上传每个块。这就是(我认为)s3manager.Uploader在幕后所做的。

您正在使用哪些特定的API和函数?我似乎在GoS3SDK中找不到您所指的函数@BadZen我已经添加了我将要使用的调用。奇怪的是,你不能使用复制函数——这就是它们的用途。也许你可以退一步。除了将文件写入磁盘之外,您唯一的其他选择是在
io.readseek
seek请求上重新发出GetObject(),并将范围字段设置为从seek的位置开始。不过,从各个方面来说,它都比已经错误的将其写入磁盘的解决方案更糟糕。感谢您的洞察力,它真的对我很有帮助