分享
golang把io.ReadCloser类型转化为[]byte
webyh · · 13287 次点击 · · 开始浏览这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。
//比如要解析resp.Body(io.ReadCloser),我们可以这样处理 body, err := ioutil.ReadAll(resp.Body)
接着,我们继续分析分析函数
func ReadAll(r io.Reader) ([]byte, error) {
return readAll(r, bytes.MinRead) //const MinRead = 512
}
//
func readAll(r io.Reader, capacity int64) (b []byte, err error) {
buf := bytes.NewBuffer(make([]byte, 0, capacity))
//func NewBuffer(buf []byte) *Buffer { return &Buffer{buf: buf} } 一个新的buffer实例
defer func() {
e := recover()
if e == nil {
return
}
//buf太大会返回相应错误
if panicErr, ok := e.(error); ok && panicErr == bytes.ErrTooLarge {
err = panicErr
} else {
panic(e)
}
}()
_, err = buf.ReadFrom(r) //关键就是这个家伙
return buf.Bytes(), err
}
来继续看看 buf.ReadFrom的实现吧:
//先看一下Buffer的定义,有帮助下面理解
type Buffer struct {
buf []byte // 最新数据存放在 buf[off : len(buf)]
off int // 从&buf[off]开始读, 从&buf[len(buf)]开始写
runeBytes [utf8.UTFMax]byte // avoid allocation of slice on each WriteByte or Rune
bootstrap [64]byte
// memory to hold first slice; helps small buffers (Printf) avoid allocation.
lastRead readOp // last read operation, so that Unread* can work correctly.
}
func (b *Buffer) ReadFrom(r io.Reader) (n int64, err error) {
b.lastRead = opInvalid // 0
if b.off >= len(b.buf) {
b.Truncate(0) //还没有写就想读,清空buf
}
for {
if free := cap(b.buf) - len(b.buf); free < MinRead {
// free的大小是总容量 - 现在占有长度
newBuf := b.buf
if b.off+free < MinRead {
//分配更大空间,分配失败会报错
newBuf = makeSlice(2*cap(b.buf) + MinRead)
}
//把读的内容b.buf[b.off:]拷贝到newbuf前面去
copy(newBuf, b.buf[b.off:])
//读写之间的差距就是应该读的buf
b.buf = newBuf[:len(b.buf)-b.off]
b.off = 0
}
//把io.Reader内容写到buf的free中去
m, e := r.Read(b.buf[len(b.buf):cap(b.buf)])
//重新调整buf的大小
b.buf = b.buf[0 : len(b.buf)+m]
n += int64(m)
//读到尾部就返回
if e == io.EOF {
break
}
if e != nil {
return n, e
}
}
return n, nil // err is EOF, so return nil explicitly
}
接下来再来看看是怎么Read进buf里面去的吧:
func (b *Buffer) Read(p []byte) (n int, err error) {
b.lastRead = opInvalid
if b.off >= len(b.buf) {
// Buffer is empty, reset to recover space.
b.Truncate(0)
if len(p) == 0 {
return
}
return 0, io.EOF
}
//就是这里咯,把b.buf[b.off:]的值写到p中去,记住copy(s1,s2)是s2写到s1中去,不要弄反咯
//而且此Buffer其实是io.ReadCloser接口转化的类型
n = copy(p, b.buf[b.off:])
b.off += n
if n > 0 {
b.lastRead = opRead
}
return
}
总之,这里分析比较少脑筋的代码就是那个ReadFrom里面修改buf大小那里的逻辑,确实有点绕。。。。。。
有疑问加站长微信联系(非本文作者)
入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889
关注微信13287 次点击
上一篇:Google 镜像站IP地址
下一篇:奇虎360 和 Go
添加一条新回复
(您需要 后才能回复 没有账号 ?)
- 请尽量让自己的回复能够对别人有帮助
- 支持 Markdown 格式, **粗体**、~~删除线~~、
`单行代码` - 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
- 图片支持拖拽、截图粘贴等方式上传
收入到我管理的专栏 新建专栏
//比如要解析resp.Body(io.ReadCloser),我们可以这样处理 body, err := ioutil.ReadAll(resp.Body)
接着,我们继续分析分析函数
func ReadAll(r io.Reader) ([]byte, error) {
return readAll(r, bytes.MinRead) //const MinRead = 512
}
//
func readAll(r io.Reader, capacity int64) (b []byte, err error) {
buf := bytes.NewBuffer(make([]byte, 0, capacity))
//func NewBuffer(buf []byte) *Buffer { return &Buffer{buf: buf} } 一个新的buffer实例
defer func() {
e := recover()
if e == nil {
return
}
//buf太大会返回相应错误
if panicErr, ok := e.(error); ok && panicErr == bytes.ErrTooLarge {
err = panicErr
} else {
panic(e)
}
}()
_, err = buf.ReadFrom(r) //关键就是这个家伙
return buf.Bytes(), err
}
来继续看看 buf.ReadFrom的实现吧:
//先看一下Buffer的定义,有帮助下面理解
type Buffer struct {
buf []byte // 最新数据存放在 buf[off : len(buf)]
off int // 从&buf[off]开始读, 从&buf[len(buf)]开始写
runeBytes [utf8.UTFMax]byte // avoid allocation of slice on each WriteByte or Rune
bootstrap [64]byte
// memory to hold first slice; helps small buffers (Printf) avoid allocation.
lastRead readOp // last read operation, so that Unread* can work correctly.
}
func (b *Buffer) ReadFrom(r io.Reader) (n int64, err error) {
b.lastRead = opInvalid // 0
if b.off >= len(b.buf) {
b.Truncate(0) //还没有写就想读,清空buf
}
for {
if free := cap(b.buf) - len(b.buf); free < MinRead {
// free的大小是总容量 - 现在占有长度
newBuf := b.buf
if b.off+free < MinRead {
//分配更大空间,分配失败会报错
newBuf = makeSlice(2*cap(b.buf) + MinRead)
}
//把读的内容b.buf[b.off:]拷贝到newbuf前面去
copy(newBuf, b.buf[b.off:])
//读写之间的差距就是应该读的buf
b.buf = newBuf[:len(b.buf)-b.off]
b.off = 0
}
//把io.Reader内容写到buf的free中去
m, e := r.Read(b.buf[len(b.buf):cap(b.buf)])
//重新调整buf的大小
b.buf = b.buf[0 : len(b.buf)+m]
n += int64(m)
//读到尾部就返回
if e == io.EOF {
break
}
if e != nil {
return n, e
}
}
return n, nil // err is EOF, so return nil explicitly
}
接下来再来看看是怎么Read进buf里面去的吧:
func (b *Buffer) Read(p []byte) (n int, err error) {
b.lastRead = opInvalid
if b.off >= len(b.buf) {
// Buffer is empty, reset to recover space.
b.Truncate(0)
if len(p) == 0 {
return
}
return 0, io.EOF
}
//就是这里咯,把b.buf[b.off:]的值写到p中去,记住copy(s1,s2)是s2写到s1中去,不要弄反咯
//而且此Buffer其实是io.ReadCloser接口转化的类型
n = copy(p, b.buf[b.off:])
b.off += n
if n > 0 {
b.lastRead = opRead
}
return
}
总之,这里分析比较少脑筋的代码就是那个ReadFrom里面修改buf大小那里的逻辑,确实有点绕。。。。。。