Golang bufio包源码分析

go 源码1.10.3   bufio.go

 

一、bufio介绍

bufio实现了带缓冲的IO功能,它是在io.Reader和io.Writer接口对象上提供了进一步的封装,从而提供了更加丰富的操作方法。bufio包主要

 

二、bufio.Reader

1.结构体

type Reader struct {
	buf          []byte    //缓冲区的数据
	rd           io.Reader // 底层的io.Reader
	r, w         int       //  r ,w分别表示 buf中读和写的指针位置
	err          error    //记录本次读取的error,后续操作中调用readErr函数后会重置err
	lastByte     int      //记录读取的最后一个字节(用于撤销)
	lastRuneSize int      //记录读取的最后一个字符(Rune)的长度(用于撤销)
}

bufio.Reader封装了io.Reader对象,并提供了带缓冲的功能。

 

2. 初始化方法

func NewReaderSize(rd io.Reader, size int) *Reader {
	// Is it already a Reader?
	b, ok := rd.(*Reader)
	if ok && len(b.buf) >= size {
		return b
	}
	if size < minReadBufferSize {
		size = minReadBufferSize
	}
	r := new(Reader)
	r.reset(make([]byte, size), rd)
	return r
}

         size用于指定缓冲区的大小,如果size小于minReadBufferSize,则重置size的值为minReadBufferSize(16)。如果该rd是*bufio.Reader对象,并且rd的缓冲区大于size,则不会创建Reader对象,而是直接返回原来的rd对象。否则会创建一个*bufio.Reader对象,并指定buf的大小为size。

 

    

const (
	defaultBufSize = 4096
)


func NewReader(rd io.Reader) *Reader {
	return NewReaderSize(rd, defaultBufSize)
}

创建缓冲区默认大小为defaultBufSize(4096)的*bufio.Reader对象

 

3.Reader常用方法

   

func (b *Reader) Size() int { return len(r.buf) }

  Size方法返回底层缓冲区的大小

 

func (b *Reader) Reset(r io.Reader) {
	b.reset(b.buf, r)
}

func (b *Reader) reset(buf []byte, r io.Reader) {
	*b = Reader{
		buf:          buf,
		rd:           r,
		lastByte:     -1,
		lastRuneSize: -1,
	}
}

   Reset方法丢弃所有缓冲数据,重置所有状态,并切换reader到r,从而从r中读取数据。

 

func (b *Reader) fill() {
	// Slide existing data to beginning.
	if b.r > 0 {
		/*
		将buf中未读的数据copy到buf中首部位置
		重置r和w 位置
		*/
		copy(b.buf, b.buf[b.r:b.w])
		b.w -= b.r
		b.r = 0
	}

	if b.w >= len(b.buf) {
		panic("bufio: tried to fill full buffer")
	}

	// Read new data: try a limited number of times.
	/*
	maxConsecutiveEmptyReads是最多尝试次数
	从rd Reader中读取数据到缓冲区buf中,并重置w的位置索引
	*/
	for i := maxConsecutiveEmptyReads; i > 0; i-- {
		n, err := b.rd.Read(b.buf[b.w:])
		if n < 0 {
			panic(errNegativeRead)
		}
		b.w += n
		if err != nil {
			b.err = err
			return
		}
		if n > 0 {
			return
		}
	}
	b.err = io.ErrNoProgress
}

     fill方法用于将缓冲区读满,可以读入的最大长度是:len(buf)-未读的字节数,如果尝试读取了maxConsecutiveEmptyReads(100)次都没有读取到数据,则会返回。

  

func (b *Reader) Peek(n int) ([]byte, error) {
	if n < 0 {
		return nil, ErrNegativeCount
	}

	/*
	如果buf中未读的字节数小于n
	并且buf中未读的字节数小于buf的总大小
	并且err为nil
	满足以上3个条件,则调用fill方法尝试从Reader中读取部分数据块
	*/
	for b.w-b.r < n && b.w-b.r < len(b.buf) && b.err == nil {
		b.fill() // b.w-b.r < len(b.buf) => buffer is not full
	}

	/*
	如果n大于buf的长度,则返回所有未读的内容,和ErrBufferFull的错误信息
	*/
	if n > len(b.buf) {
		return b.buf[b.r:b.w], ErrBufferFull
	}

	// 0 <= n <= len(b.buf)
	var err error
	/*
	如果n大于可读的长度,则返回error信息
	*/
	if avail := b.w - b.r; avail < n {
		// not enough data in buffer
		n = avail
		err = b.readErr()
		if err == nil {
			err = ErrBufferFull
		}
	}
	return b.buf[b.r : b.r+n], err
}

       Peek返回输入流的前n个字节,而不会移动读取位置。该操作不会将数据读出,只是引用,引用的数据在下一次读取操作之前是有效的,如果Peek返回的切片长度比n小,它也会返会一个错误说明原因。如果n比缓冲尺寸还大,返回的错误将是ErrBufferFull。

 


                
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值