golang bufio

测试一下golang库函数里面bufio模块代码,Readline根据'\n'切分数据

package main

import (
	"bytes"
	"errors"
	"fmt"
	"io"
	"time"
)

type Reader struct {
	buf          []byte
	rd           io.Reader // reader provided by the client
	r, w         int       // buf read and write positions
	err          error
	lastByte     int
	lastRuneSize int
}

const minReadBufferSize = 16
const maxConsecutiveEmptyReads = 100

var errNegativeRead = errors.New("bufio: reader returned negative count from Read")
var ErrBufferFull = errors.New("bufio: buffer full")

func (b *Reader) readErr() error {
	err := b.err
	b.err = nil
	return err
}

// fill reads a new chunk into the buffer.
func (b *Reader) fill() {
	// Slide existing data to beginning.
	//fmt.Printf("reader r %v\n", b.r)
	if b.r > 0 {
		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.
	//如果一直读取失败,则最多读取100次
	for i := maxConsecutiveEmptyReads; i > 0; i-- {
		n, err := b.rd.Read(b.buf[b.w:])
		//fmt.Printf(" count %v \n", n)
		if n < 0 {
			panic(errNegativeRead)
		}
		b.w += n
		if err != nil {
			b.err = err
			return
		}
		if n > 0 {
			return
		}
	}
	b.err = io.ErrNoProgress
}

func (b *Reader) Buffered() int { return b.w - b.r }

func (b *Reader) ReadSlice(delim byte) (line []byte, err error) {
	for {
		// Search buffer.
		//fmt.Printf("bytes index %v err %v \n", bytes.IndexByte(b.buf[b.r:b.w], delim), b.err)
		if i := bytes.IndexByte(b.buf[b.r:b.w], delim); i >= 0 {
			line = b.buf[b.r : b.r+i+1]
			//fmt.Printf("line is %v \n", string(line))
			b.r += i + 1
			break
		}

		// Pending error?
		if b.err != nil {
			line = b.buf[b.r:b.w]
			b.r = b.w
			err = b.readErr()
			break
		}

		// Buffer full?
		//fmt.Printf("bufio buffered %v len buf %v\n", b.Buffered(), len(b.buf))

		if b.Buffered() >= len(b.buf) {
			b.r = b.w
			line = b.buf
			err = ErrBufferFull
			break
		}

		b.fill() // buffer is not full
	}

	// Handle last byte, if any.
	if i := len(line) - 1; i >= 0 {
		b.lastByte = int(line[i])
		b.lastRuneSize = -1
	}

	return
}

func (b *Reader) ReadLine() (line []byte, isPrefix bool, err error) {
	line, err = b.ReadSlice('\n')
	if err == ErrBufferFull {
		// Handle the case where "\r\n" straddles the buffer.
		if len(line) > 0 && line[len(line)-1] == '\r' {
			// Put the '\r' back on buf and drop it from line.
			// Let the next call to ReadLine check for "\r\n".
			if b.r == 0 {
				// should be unreachable
				panic("bufio: tried to rewind past start of buffer")
			}
			b.r--
			line = line[:len(line)-1]
		}
		return line, true, nil
	}

	if len(line) == 0 {
		if err != nil {
			line = nil
		}
		return
	}
	err = nil

	if line[len(line)-1] == '\n' {
		drop := 1
		if len(line) > 1 && line[len(line)-2] == '\r' {
			drop = 2
		}
		line = line[:len(line)-drop]
	}
	return
}

func main() {
	reader := bytes.NewReader([]byte("absc\r\nddd\n"))

	b := &Reader{
		buf:          make([]byte, 100),
		rd:           reader,
		lastByte:     -1,
		lastRuneSize: -1,
	}
	for {
		line, isPrefix, err := b.ReadLine()
		fmt.Printf("line %v / prefix %v / err %v\n", string(line), isPrefix, err)

		if err == io.EOF {
			break
		}

		time.Sleep(1 * time.Second)
	}

}

输出结果:

line absc / prefix false / err <nil>
line ddd / prefix false / err <nil>
line  / prefix false / err EOF


你可能感兴趣的:(golang bufio)