Open wuyongxiu opened 7 years ago
在 io 包里有三个接口时常会相互转换 io.Reader io.ReadCloser 和 io.ReadSeeker
Reader接口封装了基本的 Read 方法,Read 方法读取长度为 len(p)的字节到 p 中,它返回读取到的字节长度(0<=n<=len(p))和遇到的任何错误。
type Reader interface{ Read( p []byte) (n int, err error) }
ReadCloser 接口封装了Reader和Closer接口,所以它具有基本的Read和Close方法。
type ReadCloser interface{ Reader Closer }
ReadSeeker 接口封装了基本的Read和Seek方法,Seek方法可以设定下一次读写的位移。
type ReadSeeker interface{ Reader Seeker }
go语言包 ioutil 提供了NopCloser方法可以将 io.Reader 封装为 io.ReadCloser func NopCloser (r io.Reader) io.ReadCloser 参考go语言源码包(net/http),里面有很多示例,将请求或回复Body读取出来后,再利用bytes.NewReader(...)将bytes封装成 io.Reader,之后利用 ioutil.NopCloser 将io.Reader封装成 io.ReadCloser 接口
func NopCloser (r io.Reader) io.ReadCloser
这里有详细的原因和方法 http://stackoverflow.com/questions/37718191/how-do-i-go-from-io-readcloser-to-io-readseeker 原因: ReadSeeker 封装了Seek()方法,这个方法要求资源的任何位置都能被定位,例如存储在磁盘里文件,你可以随时读取文件的任意位置。而response.Body 是通过TCP连接从网络中读取数据,这些数据没有被存储,并且数据发送者不会再次发送数据给你,因此 response.Body 没有实现 io.Seeker 方法。 方法:基于以上分析,对于一些像 response.Body类型的 io.ReadCloser,将它转化为 ReadSeeker的方法就是先将 io.ReadCloser 全部读取到内存中,利用 ioutil.ReadAll() 方法,然后利用 bytes.NewReader() 方法就可以从[]byte中获得 io.ReadSeeker 它的缺点就是所有的内容都需要存储在内存中,这样会造成内存损耗。
美女请教个问题,什么情况下,需要ReadCloser呢,为什么会有这种变体?
在http响应body读取后是需要close的,这种情况就需要ReadCloser。至于为什么需要ReadCloser,可以参考:what-could-happen-if-i-dont-close-response-body-in-golang
在 io 包里有三个接口时常会相互转换 io.Reader io.ReadCloser 和 io.ReadSeeker
Reader接口封装了基本的 Read 方法,Read 方法读取长度为 len(p)的字节到 p 中,它返回读取到的字节长度(0<=n<=len(p))和遇到的任何错误。
ReadCloser 接口封装了Reader和Closer接口,所以它具有基本的Read和Close方法。
ReadSeeker 接口封装了基本的Read和Seek方法,Seek方法可以设定下一次读写的位移。
1. 如何将 Reader 转化成 ReadCloser
go语言包 ioutil 提供了NopCloser方法可以将 io.Reader 封装为 io.ReadCloser
func NopCloser (r io.Reader) io.ReadCloser
参考go语言源码包(net/http),里面有很多示例,将请求或回复Body读取出来后,再利用bytes.NewReader(...)将bytes封装成 io.Reader,之后利用 ioutil.NopCloser 将io.Reader封装成 io.ReadCloser 接口
2. 如何将Reader 或者 ReadCloser 转化为 ReadSeeker
这里有详细的原因和方法
http://stackoverflow.com/questions/37718191/how-do-i-go-from-io-readcloser-to-io-readseeker
原因: ReadSeeker 封装了Seek()方法,这个方法要求资源的任何位置都能被定位,例如存储在磁盘里文件,你可以随时读取文件的任意位置。而response.Body 是通过TCP连接从网络中读取数据,这些数据没有被存储,并且数据发送者不会再次发送数据给你,因此 response.Body 没有实现 io.Seeker 方法。
方法:基于以上分析,对于一些像 response.Body类型的 io.ReadCloser,将它转化为 ReadSeeker的方法就是先将 io.ReadCloser 全部读取到内存中,利用 ioutil.ReadAll() 方法,然后利用 bytes.NewReader() 方法就可以从[]byte中获得 io.ReadSeeker
它的缺点就是所有的内容都需要存储在内存中,这样会造成内存损耗。