golang把io.ReadCloser类型转化为[]byte

//比如要解析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大小那里的逻辑,确实有点绕。。。。。。

时间: 2024-12-27 00:37:51

golang把io.ReadCloser类型转化为[]byte的相关文章

java对byte,short,char,int,long运算时自动类型转化情况说明

大家都知道,在进行运算时,java会隐式的自动进行类型转化,那么有哪些情况会进行转化呢?总结如下: 一.算术运算符 单目运算符:+(取正)-(取负) ++(自增1) --(自减1) 1.1 +(取正)-(取负) 当操作数是byte,short,char时,会自动转化为int类型:返回结果为int. 当操作数是int,long时,不转化,原来是啥类型,还是啥类型. 1.2 ++(自增1) --(自减1) 不管操作数是啥类型,不转化. 双目运算符:+ - * / %(取余) 1.3 + - * /

Java中byte、short、char、int、long运算时自动类型转化问题

-------------------------------------------------------------------------------------------------- ★★自动(隐式.默认)类型转换与强制(显式)类型转换★★ 1) boolean类型不参与转换 2) 默认转换 A:从小到大 B:byte,short,char --? int --? long --? float --? double C:byte,short,char之间不相互转换,直接转成int类

golang的io包

package io import "io" io包提供了对I/O原语的基本接口.本包的基本任务是包装这些原语已有的实现(如os包里的原语),使之成为共享的公共接口,这些公共接口抽象出了泛用的函数并附加了一些相关的原语的操作. 因为这些接口和原语是对底层实现完全不同的低水平操作的包装,除非得到其它方面的通知,客户端不应假设它们是并发执行安全的. Index Variables type Reader type Writer type Closer type Seeker type Re

关于golang中IO相关的Buffer类浅析

io重要的接口 在介绍buffer之前,先来认识两个重要的接口,如下边所示: type Reader interface { Read(p []byte) (n int, err error) } type Writer interface { Write(p []byte) (n int, err error) } 上边两个接口在golang sdk安装目录src/io/io.go中定义.后边凡是涉及到io相关操作的,基本上都实现了这两个接口,如: 1. package bufio 中的Rea

Asp.net 面向接口可扩展框架之类型转化基础服务

新框架正在逐步完善,可喜可贺的是基础服务部分初具备模样了,给大家分享一下 由于基础服务涉及太广,也没开发完,这篇只介绍其中的类型转化部分,命名为类型转化基础服务,其实就是基础服务模块的类型转化子模块 说到类型转化必须要清楚.net的类型,类型都不清楚何来类型转化 1.Primitive类型 1.1 这个概念估计很多人都没听说过,Primitive不是一个新类型,而是.net类型中最基本的一种分类,是基元类型的意思       MS将类型分为三类:Primitive(基元类型).Complex(复

1.7—Java基本类型转化及常见错误和问题

数据类型的转换  自动类型转换 自动类型转换指的是容量小的数据类型可以自动转换为容量大的数据类型.在图1所示,黑色的实线表示无数据丢失的自动类型转换,而虚线表示在转换时可能会精度的损失. 图1 自动类型转换 可以将整型常量直接赋值给byte. short. char等类型变量,而不需要进行强制类型转换,只要不超出其表数范围 [示例1]自动类型转换特例 short  b = 12;        //合法 short  b = 1234567;    //非法 强制类型转换 强制类型转换(Cast

javascript中的隐式类型转化

javascript中的隐式类型转化 #隐式转换 ## "+" 字符串和数字 如果某个操作数是字符串或者能够通过以下步骤转换为字符串的话,+将进行拼接操作. 如果其中一个操作数是对象(包括数组),则首先对其调用`ToPrimitive`抽象操作,该抽象操作再调用`[[DefaultValue]]`,以数字作为上下文. `[1,2]+[3,4]=='1,23,4'` 原因,因为数组的valueOf操作无法得到简单的基本类型,于是它转而调用toString.因此上栗得到的是'1,23,4'

Spring mvc @initBinder 类型转化器的使用

一.单日期格式 因为是用注解完完成的后台访问,所以必须在大配置中配置包扫描器: 1.applicactionContext.xml <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-ins

jQuery源码分析系列(36) : Ajax - 类型转化器

什么是类型转化器? jQuery支持不同格式的数据返回形式,比如dataType为 xml, json,jsonp,script, or html 但是浏览器的XMLHttpRequest对象对数据的响应只有 responseText与responseXML 二种 所以现在我要定义dataType为jsonp,那么所得的最终数据是一个json的键值对,所以jQuery内部就会默认帮你完成这个转化工作 jQuery为了处理这种执行后数据的转化,就引入了类型转化器,如果没有指定类型就依据响应头Con