• Go 学习之 io.Reader 从源码了解如何编写


    参考

    Reader和Writer 接口

    接口的定义

    type Reader interface {
        Read(p []byte) (n int, err error)
    }
    
    type Writer interface {
        Write(p []byte) (n int, err error)
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    作用

    Reader 接口

    • 实现该接口的【类型(数据结构)】,可以理解为【可供数据读出的数据容器】,调用【Read方法】,即可实现从【数据容器中读取数据】

    Writer 接口

    • 实现该接口的【类型(数据结构)】,可以理解为【可供数据写入的数据容器】,调用【Write方法】,即可实现从【向数据容器中写入数据】

    Reader 接口 和 Writer 接口

    • 同时实现这两个接口的【类型(数据结构)】,可以理解为【可供数据写入和读出的数据容器】

    常用的几个实现

    围绕io.Reader/Writer,有几个常用的实现:

    • net.Conn, os.Stdin, os.File: 网络、标准输入输出、文件的流读取
    • strings.Reader: 把字符串抽象成Reader
    • bytes.Reader: 把[]byte抽象成Reader
    • bytes.Buffer: 把[]byte抽象成Reader和Writer
    • bufio.Reader/Writer: 抽象成带缓冲的流读取(比如按行读写)

    如何实现这两个接口

    Read(p []byte) (n int, err error)

    • 负责将数据读取,写入到 p []byte 中

    Write(p []byte) (n int, err error)

    • 负责 从 p []byte 中读取数据,写到需要的地方
    type Reader interface {
        Read(p []byte) (n int, err error)
    }
    
    type Writer interface {
        Write(p []byte) (n int, err error)
    }
    
    // 如何实现这两个方法
    // Read 就是将数据读取,写入到 p []byte 中
    Read(p []byte) (n int, err error)
    
    // 示例
    // /usr/local/Cellar/go@1.17/1.17.8/libexec/src/strings/reader.go
    // Read implements the io.Reader interface.
    func (r *Reader) Read(b []byte) (n int, err error) {
    	if r.i >= int64(len(r.s)) {
    		return 0, io.EOF
    	}
    	r.prevRune = -1
      // r.i 记录了当前数据读到了 哪个位置
      // n 为拷贝数据的长度 
      // copy 第一个参数为 需要填充的, 第二个参数为 被拷贝的数据
      // 若第一个参数空间 < 第二个参数长度,那么只拷贝第一个参数能容纳的长度
      // 如 b 为 []byte 2长度 ,r.s[r.i:]=“adsgsg”
      // 那么执行 copy 后,b 为“ad"
    	n = copy(b, r.s[r.i:])
    	r.i += int64(n)
    	return
    }
    
    // Write 就是从 p []byte 中读取数据,写到需要的地方
    Write(p []byte) (n int, err error)
    
    // 示例
    // /usr/local/Cellar/go@1.17/1.17.8/libexec/src/strings/builder.go
    // Write appends the contents of p to b's buffer.
    // Write always returns len(p), nil.
    func (b *Builder) Write(p []byte) (int, error) {
    	b.copyCheck()
    	b.buf = append(b.buf, p...)
    	return len(p), nil
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43

    代码详解

    代码示例

    // testReadstring
    func main() {
    	s := strings.NewReader("亲爱的提奥,梵高")
    	br := bufio.NewReader(s)
    	// ReadString 在 br 中查找 delim 并返回 delim 及其之前的所有数据。
    	// func (b *Reader) ReadString(delim byte) (line []byte, err error)
    
    	n, err := br.ReadString(',')
    	fmt.Printf("%s  %v\n", n, err) // 亲爱的提奥,  
    
    	// 如果未找到 delim 且遇到错误(通常是 io.EOF),则返回缓存中的所
    	n, err = br.ReadString(',')
    	fmt.Printf("%s  %v\n", n, err) // 梵高  EOF
    	fmt.Println(n)
    	fmt.Println(string(n))
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    Q1 | 为什么不直接使用 bufio.NewReader

    可以看到,bufio.NewReader 传入的参数需要实现了io.Reader接口,因此直接传入普通文本"亲爱的提奥,梵高" 不匹配 io.Reader接口,会显示数据类型不匹配,无法识别

    // /usr/local/Cellar/go@1.17/1.17.8/libexec/src/bufio/bufio.go
    
    // NewReader returns a new Reader whose buffer has the default size.
    func NewReader(rd io.Reader) *Reader {
    	return NewReaderSize(rd, defaultBufSize)
    }
    
    // Reader implements buffering for an io.Reader object.
    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 // last byte read for UnreadByte; -1 means invalid
    	lastRuneSize int // size of last rune read for UnreadRune; -1 means invalid
    }
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    因此,将普通文本"亲爱的提奥,梵高"通过strings.NewReader函数,转换为实现了 io.Reader接口的*strings.Reader结构,之后便可传入了bufio.NewReader函数,从而构建*bufio.Reader结构

    • 问题?为什么非得要采用 *bufio.Reader结构
      • 因为bufio包,具有的功能更多(如 换行读取,Scan 函数,可指定截断函数(如br.Split(bufio.ScanWords),按字阶段,读取)的Scan函数,以及上面示例中指定截断符号的读取一行的函数( br.ReadString(‘,’)))
        • 同时 bufio 还具有 Write函数,可将从底层读取的,重新写入到别处
      • strings 包可能只具有简单的一些读取函数
    // /usr/local/Cellar/go@1.17/1.17.8/libexec/src/strings/reader.go
    
    // NewReader returns a new Reader reading from s.
    // It is similar to bytes.NewBufferString but more efficient and read-only.
    func NewReader(s string) *Reader { return &Reader{s, 0, -1} }
    
    // A Reader implements the io.Reader, io.ReaderAt, io.ByteReader, io.ByteScanner,
    // io.RuneReader, io.RuneScanner, io.Seeker, and io.WriterTo interfaces by reading
    // from a string.
    // The zero value for Reader operates like a Reader of an empty string.
    type Reader struct {
    	s        string
    	i        int64 // current reading index
    	prevRune int   // index of previous rune; or < 0
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    分析函数调用逻辑

    s := strings.NewReader("亲爱的提奥,梵高")
    br := bufio.NewReader(s)
    
    n, err := br.ReadString(',')
    
    • 1
    • 2
    • 3
    • 4
    1 | 初始化创建 bufio.NewReader
    1. 首先s := strings.NewReader("亲爱的提奥,梵高")创建了 *strings.Reader 结构,并进行了初始化,记录了原始文本亲爱的提奥,梵高
    2. 之后 br := bufio.NewReader(s) 通过传入的*strings.Reader 结构,创建了*strings.Reader结构并进行了初始化,通过指针rd记录了引用的*strings.Reader 结构
    • strings.NewReader(“亲爱的提奥,梵高”)
    // /usr/local/Cellar/go@1.17/1.17.8/libexec/src/strings/reader.go
    
    // NewReader returns a new Reader reading from s.
    // It is similar to bytes.NewBufferString but more efficient and read-only.
    func NewReader(s string) *Reader { return &Reader{s, 0, -1} }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • br := bufio.NewReader(s)
    // /usr/local/Cellar/go@1.17/1.17.8/libexec/src/bufio/bufio.go
    
    // NewReader returns a new Reader whose buffer has the default size.
    func NewReader(rd io.Reader) *Reader {
    	return NewReaderSize(rd, defaultBufSize)
    }
    
    // NewReaderSize returns a new Reader whose buffer has at least the specified
    // size. If the argument io.Reader is already a Reader with large enough
    // size, it returns the underlying Reader.
    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
    }
    
    // 创建  bufio.NewReader 结构,并进行初始化
    func (b *Reader) reset(buf []byte, r io.Reader) {
    	*b = Reader{
    		buf:          buf,
    		rd:           r,  // 通过指针形式,引用上面传入的  strings.Reader 结构(即 亲爱的提奥,梵高)
    		lastByte:     -1,
    		lastRuneSize: -1,
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    2 | n, err := br.ReadString(‘,’) 函数的调用

    该函数作用很简单,就是返回被 delim 分割的前半部分数据

    本里中【亲爱的提奥,梵高】,delim 为【,】,返回的就是前半部分 【亲爱的提奥】

    函数调用逻辑:bufio.ReadString --> bufio.collectFragments --> bufio.ReadSlice --> bufio.fill --> strings.Read

    bufio.ReadString:【片段拼接区】对返回的数据片段【二维数组 fullBuffers [][]byte 和 frag】进行拼接,调用 bufio.Write 进行【拼接】返回

    bufio.collectFragments :【片段收集区】,由于缓存 buf 固定大小,因此创建二维数组 fullBuffers [][]byte 存储未找到 delim 的 buf,之后刷新 buf 继续寻找,指导找到 delim,此时返回的片段记作【frag】,不记录到二维数组中,之后将 数据片段【二维数组 fullBuffers [][]byte 和 frag】返回上层进行拼接

    bufio.ReadSlice:【delim寻找区】

    • 在 buf 中寻找 delim,找到后返回前半部分,记为 frag;
    • 未找到时,
      • 缓存 buf 满的情况,传给 bufio.collectFragments,记录到二维数组 fullBuffers [][]byte
      • 缓存 buf 未满情况,调用 fill 函数,补充缓存 buf,之后继续寻找 delim

    **bufio.fill:**就是调用【strings.Read函数】, 补满 buf 缓存区

    **strings.Read:**就是我们最开始讲 string 装换为 io.Reader 接口实现的 Read 函数,负责对 string 的读取

    因此可以看出,bufio 需要参数 io.Reader 的原因,就是需要【下层函数可以实现基本的数据读取功能】,之后【bufio 函数可以做更多的处理,因为自身携带缓存区 buf,所以读取之后存入缓存 buf,可以进行筛选、截断、甚至写入到其他地方】

    所以我们定义一个类型后,【实现其Read 方法func (r *Reader) Read(b []byte) (n int, err error),就是将数据读入到 b []byte中】,之后便可通过bufio.NewReader方法创建bufio.Reader,从而调用 bufio 更多处理功能

    2.1 | bufio ReadString
    // /usr/local/Cellar/go@1.17/1.17.8/libexec/src/bufio/bufio.go
    
    // ReadString reads until the first occurrence of delim in the input,
    // returning a string containing the data up to and including the delimiter.
    // If ReadString encounters an error before finding a delimiter,
    // it returns the data read before the error and the error itself (often io.EOF).
    // ReadString returns err != nil if and only if the returned data does not end in
    // delim.
    // For simple uses, a Scanner may be more convenient.
    func (b *Reader) ReadString(delim byte) (string, error) {
      // collectFragments(delim):以 delim 作为分割符,对传入的数据进行分割
    	full, frag, n, err := b.collectFragments(delim)
    	// Allocate new buffer to hold the full pieces and the fragment.
    	var buf strings.Builder
      // 对 buf 进行扩展,存储被 delim 分割的前部分数据
    	buf.Grow(n)   
    	// Copy full pieces and fragment in.
      // full 为不包含 delim 的 buf 长度数据
    	for _, fb := range full {
    		buf.Write(fb)
    	}
      // frag 为 buf 中被 delim 截断的前部分数据
    	buf.Write(frag)
    	return buf.String(), err
    }
    
    // Write appends the contents of p to b's buffer.
    // Write always returns len(p), nil.
    func (b *Builder) Write(p []byte) (int, error) {
    	b.copyCheck()
    	b.buf = append(b.buf, p...)
    	return len(p), nil
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    2.2 | bufio collectFragments 函数
    // /usr/local/Cellar/go@1.17/1.17.8/libexec/src/bufio/bufio.go
    
    // collectFragments reads until the first occurrence of delim in the input. It
    // returns (slice of full buffers, remaining bytes before delim, total number
    // of bytes in the combined first two elements, error).
    // The complete result is equal to
    // `bytes.Join(append(fullBuffers, finalFragment), nil)`, which has a
    // length of `totalLen`. The result is structured in this way to allow callers
    // to minimize allocations and copies.
    func (b *Reader) collectFragments(delim byte) (fullBuffers [][]byte, finalFragment []byte, totalLen int, err error) {
    	var frag []byte
    	// Use ReadSlice to look for delim, accumulating full buffers.
    	for {
    		var e error
        // 按照 delim 分割分隔符 读取一行
    		frag, e = b.ReadSlice(delim) 
        
        // 1. 正常情况,直接 break,进行返回
    		if e == nil { // got final fragment
    			break
    		}
        // 2. 其他错误
    		if e != ErrBufferFull { // unexpected error
    			err = e
    			break
    		}
    
    		// Make a copy of the buffer.
        // 3. buf 空间不足错误 ErrBufferFull
        // 此种情况就是 buf 是满的,同时没找到 delim 分割符,因此此时要记录此 buf
        // 之后清空 buf,用于读取新数据,继续寻找 delim 分隔符
    		buf := make([]byte, len(frag))
    		copy(buf, frag)
    		fullBuffers = append(fullBuffers, buf)
    		totalLen += len(buf)
    	}
    
    	totalLen += len(frag)
    	return fullBuffers, frag, totalLen, err
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    2.3 | bufio ReadSlice
    // ReadSlice reads until the first occurrence of delim in the input,
    // returning a slice pointing at the bytes in the buffer.
    // The bytes stop being valid at the next read.
    // If ReadSlice encounters an error before finding a delimiter,
    // it returns all the data in the buffer and the error itself (often io.EOF).
    // ReadSlice fails with error ErrBufferFull if the buffer fills without a delim.
    // Because the data returned from ReadSlice will be overwritten
    // by the next I/O operation, most clients should use
    // ReadBytes or ReadString instead.
    // ReadSlice returns err != nil if and only if line does not end in delim.
    func (b *Reader) ReadSlice(delim byte) (line []byte, err error) {
    	s := 0 // search start index
    	for {
    		// Search buffer.
        // i 为 bytes.IndexByte 返回的最近的 delim 符号位置下标
        // b.r 为缓存 buf 的初始位置,即目前读到的位置
        // b.w 为缓存 buf 的尾部位置,即数据的最大长度
        // s 为上一次,分割掉 字符串的长度,本次不再读取,所以在剩余部分 b.buf[b.r+s:b.w] 中进行分割
        
        // 1. 在 buf 中找到 delim 分割符,此时 i >= 0
    		if i := bytes.IndexByte(b.buf[b.r+s : b.w], delim); i >= 0 {
    			i += s
          // 返回被 delim 分割的前部分
    			line = b.buf[b.r : b.r+i+1]  // 就是目前 被 delim 分割的一行  虽然 return 没有写,但是由于是命名返回值,可以直接返回
    			b.r += i + 1
    			break
    		}
    		
        // 2. 在当前 buf 中未找到 delim 分隔符,此时存在两种情况
    		// Pending error?
    		if b.err != nil {
    			line = b.buf[b.r:b.w]
    			b.r = b.w
    			err = b.readErr()
    			break
    		}
    
    		// Buffer full?
        // 2.1 在当前 buf 中未找到 delim 分隔符,同时缓存区 buf 还是满的,此时返回错误,交给上层处理
        // 上层会将其存储在 二维数组中  fullBuffers [][]byte
        // 之后上层会继续调用 ReadSlice 函数 寻找 delim
        // 若还没找到 delim,同时缓存区仍满,继续存入 fullBuffers [][]byte
        // 知道最后找 delim ,此时返回的片段叫做 frag []byte
        // 最后 将 fullBuffers [][]byte 和 frag []byte 拼接,就是 delim 分割的前部分
    		if b.Buffered() >= len(b.buf) {
    			b.r = b.w
    			line = b.buf
    			err = ErrBufferFull
    			break
    		}
    		
        // 2.2 在当前 buf 中未找到 delim 分隔符,同时缓存区 buf 还是满的,此时清空前面已读的,然后不全buf 进行继续寻找
        
        // s 表示未读部分,但是已扫描过,没有找到 delim 分割符
    		s = b.w - b.r // do not rescan area we scanned before
    
    		// 保证缓存空间 buf 一直是满的
        // 前面读走的 b.r 长度数据,在此处进行填充,填充新数据到 buf 的末尾
    		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
    }
    
    // Buffered returns the number of bytes that can be read from the current buffer.
    func (b *Reader) Buffered() int { return b.w - b.r }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    2.4 | bufio fill
    // fill reads a new chunk into the buffer.
    func (b *Reader) fill() {
    	// Slide existing data to beginning.
      // 滑动添加数据,将首位置 b.r 
      // b.r 为缓存 buf 的初始位置,即目前读到的位置
      // b.w 为缓存 buf 的尾部位置,即数据的最大长度
      // b.r 之前为已读过, b.r-b.w 为未读过
      // 此处 copy(b.buf, b.buf[b.r:b.w]) 相当于将未读过的 b.buf[b.r:b.w] 进行前移,这样 buf 后面会空出(已读过的空间 长度为b.r)
      // 前移之后,记得更新下标,目前读到的位置为 0 即 b.r = 0,数据的最大长度也进行更新 b.w -= b.r
    	if b.r > 0 {
    		copy(b.buf, b.buf[b.r:b.w])
    		b.w -= b.r
    		b.r = 0
    	}
    
      // 当前数据的最大长度  和 缓存空间 buf 一样大,不需要继续填充
      // panic 表示无法进行填充了
    	if b.w >= len(b.buf) {
    		panic("bufio: tried to fill full buffer")
    	}
    
    	// Read new data: try a limited number of times.
    	for i := maxConsecutiveEmptyReads; i > 0; i-- {
        // b.buf[b.w:] 表示 buf 的剩余可填充空间
        // b.rd.Read 调用指针指向的 strings.Read 函数进行填充
    		n, err := b.rd.Read(b.buf[b.w:])
    		if n < 0 {
    			panic(errNegativeRead)
    		}
        // 读取数据的时候,会自动给末尾位置  b.w 更新索引下标
    		b.w += n
    		if err != nil {
    			b.err = err
    			return
    		}
    		if n > 0 {
    			return
    		}
    	}
    	b.err = io.ErrNoProgress
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    2.5 | strings read
    // Read implements the io.Reader interface.
    func (r *Reader) Read(b []byte) (n int, err error) {
    	if r.i >= int64(len(r.s)) {
    		return 0, io.EOF
    	}
    	r.prevRune = -1
      // r.i 记录了当前数据读到了 哪个位置
      // n 为拷贝数据的长度 
      // copy 第一个参数为 需要填充的, 第二个参数为 被拷贝的数据
      // 若第一个参数空间 < 第二个参数长度,那么只拷贝第一个参数能容纳的长度
      // 如 b 为 []byte 2长度 ,r.s[r.i:]=“adsgsg”
      // 那么执行 copy 后,b 为“ad"
    	n = copy(b, r.s[r.i:])
    	r.i += int64(n)
    	return
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    bufio 包其他功能测试

    package main
    
    import (
    	"bytes"
    	"fmt"
    	// "os"
    	"strings"
    	"bufio"
    )
    
    //type Reader struct { ... }
    
    // NewReaderSize 将 rd 封装成一个带缓存的 bufio.Reader 对象,
    // 缓存大小由 size 指定(如果小于 16 则会被设置为 16)。
    // 如果 rd 的基类型就是有足够缓存的 bufio.Reader 类型,则直接将
    // rd 转换为基类型返回。
    //func NewReaderSize(rd io.Reader, size int) *Reader
    
    // NewReader 相当于 NewReaderSize(rd, 4096)
    //func NewReader(rd io.Reader) *Reader
    
    // bufio.Reader 实现了如下接口:
    // io.Reader
    // io.WriterTo
    // io.ByteScanner
    // io.RuneScanner
    
    func testRead(){
    	s := strings.NewReader("ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890")
    	br := bufio.NewReader(s)
    
    	buf:=make([]byte,1024)//sliece
    	n, err := br.Read(buf)
    
    
    	// buf:= [512]byte{}//array
    	// n, err := br.Read(buf[:])//将array切片
    
    	fmt.Printf("%s %v %v\n", buf[:n], n, err) // ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890 36 
    }
    
    func testReadstring(){
    	s := strings.NewReader("亲爱的提奥,梵高")
    	br := bufio.NewReader(s)
       // ReadString 在 br 中查找 delim 并返回 delim 及其之前的所有数据。
       // func (b *Reader) ReadString(delim byte) (line []byte, err error)
    
    	n, err := br.ReadString(',')
    	fmt.Printf("%s  %v\n", n, err) // 亲爱的提奥,  
    
    	// 如果未找到 delim 且遇到错误(通常是 io.EOF),则返回缓存中的所
    	n, err = br.ReadString(',')
    	fmt.Printf("%s  %v\n", n, err) // 梵高  EOF
    	fmt.Println(n)
    	fmt.Println(string(n))
    
    }
    
    func TestReadBytes() {
    	// ReadBytes 功能同 ReadSlice,只不过返回的是缓存的拷贝。
    	// func (b *Reader) ReadBytes(delim byte) (line []byte, err error)
    	s := strings.NewReader("ABC,你好啊,HIJ")
    	br := bufio.NewReader(s)
    	line, err := br.ReadBytes(',')
    	if err != nil {
    	   panic(err)
    	} 
    	fmt.Printf("%s  %v\n", line, err) //
    	line, err = br.ReadBytes(',')
    	if err != nil {
    	   panic(err)
    	} 
    	fmt.Printf("%s  %v\n", line, err) //
    	fmt.Println(line)
    	fmt.Println(string(line))
    
    
    }
    // ReadLine 是一个低水平的行读取原语,大多数情况下,应该使用
    // ReadBytes('\n') 或 ReadString('\n'),或者使用一个 Scanner。
    //
    // ReadLine 通过调用 ReadSlice 方法实现,返回的也是缓存的切片。用于
    // 读取一行数据,不包括行尾标记(\n 或 \r\n)。
    //
    // 只要能读出数据,err 就为 nil。如果没有数据可读,则 isPrefix 返回
    // false,err 返回 io.EOF。
    //
    // 如果找到行尾标记,则返回查找结果,isPrefix 返回 false。
    // 如果未找到行尾标记,则:
    // 1、缓存不满,则将缓存填满后再次查找。
    // 2、缓存是满的,则返回整个缓存,isPrefix 返回 true。
    //
    // 整个数据尾部“有一个换行标记”和“没有换行标记”的读取结果是一样。
    //
    // 如果 ReadLine 读取到换行标记,则调用 UnreadByte 撤销的是换行标记,
    // 而不是返回的数据。
    func testReadline(){
    	s := strings.NewReader("ABC,你好啊,HIJ,李银河")
    	br := bufio.NewReader(s)
    	var finish bool	
    	line,finish ,err := br.ReadLine()
    	if err != nil {
    	   panic(err)
    	} 
    	fmt.Println(line,finish)
    	fmt.Println(string(line))
    }
    
    
    
    //type Writer struct { ... }
    
    // NewWriterSize 将 wr 封装成一个带缓存的 bufio.Writer 对象,
    // 缓存大小由 size 指定(如果小于 4096 则会被设置为 4096)。
    // 如果 wr 的基类型就是有足够缓存的 bufio.Writer 类型,则直接将
    // wr 转换为基类型返回。
    //func NewWriterSize(wr io.Writer, size int) *Writer
    
    // NewWriter 相当于 NewWriterSize(wr, 4096)
    //func NewWriter(wr io.Writer) *Writer
    
    //func NewWriter(wr io.Writer) *Writer
    
    // bufio.Writer 实现了如下接口:
    // io.Writer
    // io.ReaderFrom
    // io.ByteWriter
    
    // WriteString 功能同 Write,只不过写入的是字符串
    // func (b *Writer) WriteString(s string) (int, error)
    
    // WriteRune 向 b 写入 r 的 UTF-8 编码,返回 r 的编码长度。
    // func (b *Writer) WriteRune(r rune) (size int, err error)
    
    // Flush 将缓存中的数据提交到底层的 io.Writer 中
    // func (b *Writer) Flush() error
    
    // Available 返回缓存中未使用的空间的长度
    // func (b *Writer) Available() int
    
    // Buffered 返回缓存中未提交的数据的长度
    // func (b *Writer) Buffered() int
    
    // Reset 将 b 的底层 Writer 重新指定为 w,同时丢弃缓存中的所有数据,复位
    // 所有标记和错误信息。相当于创建了一个新的 bufio.Writer。
    // func (b *Writer) Reset(w io.Writer)
    
    func TestWriteTo() {
    	// WriteTo方法实现了io.WriterTo接口。
    	// func (b *Reader) WriteTo(w io.Writer) (n int64, err error)
    	s := strings.NewReader("李银河")
    	br := bufio.NewReader(s)
    	b := bytes.NewBuffer(make([]byte, 0))
    	br.WriteTo(b)
    	fmt.Println(b)
    	fmt.Printf("%T\n",b)
    	fmt.Println(b.String())
    } 
    
    
    
    
    func TestNewWriter() {
     
    	// NewWriter创建一个具有默认大小缓冲、写入w的*Writer。
    	// 相当于 NewWriterSize(wr, 4096)
    	// func NewWriter(w io.Writer) *Writer
      
    	// Buffered()返回缓冲中已使用的字节数。
    	// func (b *Writer) Buffered() int
      
    	// Available()返回缓冲中还有多少字节未使用。
    	// func (b *Writer) Available() int
      
    	// Reset丢弃缓冲中的数据,清除任何错误,将b重设为将其输出写入w。
    	// func (b *Writer) Reset(w io.Writer)
      
    	b := bytes.NewBuffer(make([]byte, 0))
    	bw := bufio.NewWriter(b)
      
    	fmt.Println(bw.Available(), bw.Buffered()) // 4096  0
    	bw.WriteString("card")
    	fmt.Println(bw.Available(), bw.Buffered()) // 4092  4
      
    	bw.Reset(b)
    	fmt.Println(bw.Available(), bw.Buffered()) // 4096  0
    	fmt.Println(bw)
    
    }
    
    
    func TestWriteString() {
    	// WriteString 同 Write,只不过写入的是字符串
    	// func (b *Writer) WriteString(s string) (int, error)
    	b := bytes.NewBuffer(make([]byte, 0))
    	bw := bufio.NewWriter(b)
    	bw.WriteString("hello world")
    	bw.Flush()//y一定要flush到底层//y一定要flush到底层//y一定要flush到底层
    	fmt.Printf("%s\n", b)
    } 
    
    func TestWritebytes() {
    	// WriteString 同 Write,只不过写入的是字符串
    	// func (b *Writer) WriteString(s string) (int, error)
    	b := bytes.NewBuffer(make([]byte, 0))
    	bw := bufio.NewWriter(b)
    	bw.WriteByte('h')
    	bw.Flush()//y一定要flush到底层//y一定要flush到底层//y一定要flush到底层
    	fmt.Printf("%s\n", b)
    } 
    func TestWriterune() {
    	// WriteString 同 Write,只不过写入的是字符串
    	// func (b *Writer) WriteString(s string) (int, error)
    	b := bytes.NewBuffer(make([]byte, 0))
    	bw := bufio.NewWriter(b)
    	bw.WriteRune('h')
    	bw.Flush()//y一定要flush到底层//y一定要flush到底层//y一定要flush到底层
    	fmt.Printf("%s\n", b)
    } 
    
    
    
    func TestReadFrom() {
    	// ReadFrom实现了io.ReaderFrom接口。
    	//将r读到b
    	// func (b *Writer) ReadFrom(r io.Reader) (n int64, err error)
    	// ReadFrom无需使用Flush
    	// b := bytes.NewBuffer(make([]byte, 0))
    	b :=bytes.NewBufferString("你好啊")
    	s := strings.NewReader(",李银河")
    	bw := bufio.NewWriter(b)
    	bw.ReadFrom(s)
    	fmt.Println(b)
    } 
    
    
     
    func TestReadWriter() {
    	// ReadWriter类型保管了指向Reader和Writer类型的指针
    	// 实现了io.ReadWriter接口。
      
    	// NewReadWriter 生成bufio.ReadWriter对象
    	// func NewReadWriter(r *Reader, w *Writer) *ReadWriter
    	b := bytes.NewBuffer(make([]byte, 0))
    	bw := bufio.NewWriter(b)
    	s := strings.NewReader("hello world")
    	br := bufio.NewReader(s)
    	rw := bufio.NewReadWriter(br, bw)
      
    	word, err := rw.ReadString(' ')
    	if err != nil {
    	   panic(err)
    	}
    	fmt.Printf("%s\n", word) // hello
      
    	_, err = rw.WriteString(",I'm coming")
    	if err != nil {
    	   panic(err)
    	}
    	rw.Flush()
    	fmt.Println(b)
    }
    
    
    
    func TestNewScanner()  {
    	// Scanner 提供了一个方便的接口来读取数据,例如遍历多行文本中的行。Scan 方法会通过
    	// 一个“匹配函数”读取数据中符合要求的部分,跳过不符合要求的部分。“匹配函数”由调
    	// 用者指定。本包中提供的匹配函数有“行匹配函数”、“字节匹配函数”、“字符匹配函数”
    	// 和“单词匹配函数”,用户也可以自定义“匹配函数”。默认的“匹配函数”为“行匹配函
    	// 数”,用于获取数据中的一行内容(不包括行尾标记)
    	//
    	// Scanner 使用了缓存,所以匹配部分的长度不能超出缓存的容量。默认缓存容量为 4096 -
    	// bufio.MaxScanTokenSize,用户可以通过 Buffer 方法指定自定义缓存及其最大容量。
    	//
    	// Scan 在遇到下面的情况时会终止扫描并返回 false(扫描一旦终止,将无法再继续):
    	// 1、遇到 io.EOF
    	// 2、遇到读写错误
    	// 3、“匹配部分”的长度超过了缓存的长度
    	//
    	// 如果需要对错误进行更多的控制,
    	// 或“匹配部分”超出缓存容量,或需要连续扫描,
    	// 则应该使用 bufio.Reader
    	// func NewScanner(r io.Reader) *Scanner
      
    	// Bytes方法返回最近一次Scan调用生成的token。
    	// 底层数组指向的数据可能会被下一次Scan的调用重写。
    	// func (s *Scanner) Bytes() []byte
      
      
    	// Buffer()方法设置扫描时使用的初始缓冲区和最大值
    	// 默认情况下,Scan使用内部缓冲区并设置MaxScanTokenSize的最大令牌大小
    	s := strings.NewReader("周起\n卡牌\n程序员\n")
    	bs := bufio.NewScanner(s)
    	bs.Buffer(make([]byte,0),bufio.MaxScanTokenSize)
    	for bs.Scan() {
    	   // 周起
    	   // 卡牌
    	   // 程序员
    	   fmt.Printf("%s\n", bs.Bytes())
    	}
     
    }
    
    func TestScan()  {
    	// Scan方法获取当前位置的token(该token可以通过Bytes或Text方法获得),
    	// 并让Scanner的扫描位置移动到下一个token。
    	// 当扫描因为抵达输入流结尾或者遇到错误而停止时,
    	// 本方法会返回false。在Scan方法返回false后,
    	// Err方法将返回扫描时遇到的任何错误;
    	// 除非是io.EOF,此时Err会返回nil。
    	// func (s *Scanner) Scan() bool
    	s := strings.NewReader("周起 卡牌 程序员")
    	bs := bufio.NewScanner(s)
    	bs.Split(bufio.ScanWords)
    	for bs.Scan()  {
    	   fmt.Printf("%s %s\n", bs.Text(), bs.Bytes())
    	}
    } 
    
      
     func TestScanBytes()  {
    	// Bytes方法返回最近一次Scan调用生成的token。
    	// 底层数组指向的数据可能会被下一次Scan的调用重写。
    	s := strings.NewReader("abcd")
    	bs := bufio.NewScanner(s)
    	bs.Split(bufio.ScanBytes)
    	for bs.Scan(){
    	   // a
    	   // b
    	   // c
    	   // d
    	   fmt.Printf("%s\n", bs.Bytes())
    	}
     }
      
     func TestScanRunes()  {
    	// ScanRunes是用于Scanner类型的分割函数(符合SplitFunc),
    	// 本函数会将每个utf-8编码的unicode码值作为一个token返回。
    	s := strings.NewReader("周起卡牌程序员")
    	bs := bufio.NewScanner(s)
    	bs.Split(bufio.ScanRunes)
    	for bs.Scan()  {
    	   // 周
    	   // 起
    	   // 卡
    	   // 牌
    	   // 程
    	   // 序
    	   // 员
    	   fmt.Printf("%s\n", bs.Text())
    	}
     }
      
     func TestScanWords()  {
    	// ScanRunes是用于Scanner类型的分割函数(符合SplitFunc),
    	// 本函数会将空白(参见unicode.IsSpace)
    	// 分隔的片段(去掉前后空白后)作为一个token返回。
    	// 本函数永远不会返回空字符串。
    	s := strings.NewReader("我 是 卡 牌")
    	bs := bufio.NewScanner(s)
    	bs.Split(bufio.ScanWords)
    	for bs.Scan(){
    	   // 我
    	   // 是
    	   // 卡
    	   // 牌
    	   fmt.Printf("%s\n", bs.Text())
    	}
     }
      
     func TestScanLines()  {
    	// 将每一行文本去掉末尾的换行标记作为一个token返回
    	// 此函数的bs.Scan()的默认值
    	s := strings.NewReader("卡牌\n周起\n程序员\n")
    	bs := bufio.NewScanner(s)
    	bs.Split(bufio.ScanLines)
    	for bs.Scan(){
    	   // 卡牌
    	   // 周起
    	   // 程序员
    	   fmt.Printf("%s\n", bs.Text())
    	}
    } 
    
    func main(){
    	testRead()
    	testReadstring()
    	TestReadBytes()
    	testReadline()
    	TestWriteTo() 
    	TestWriteString()
    	TestWritebytes()
    	TestWriterune()
    	TestReadFrom()
    	TestScan()
    	TestNewScanner() 
    	TestScanBytes()
    	TestScanWords()
    	TestScanRunes()
    	TestScanLines()
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265
    • 266
    • 267
    • 268
    • 269
    • 270
    • 271
    • 272
    • 273
    • 274
    • 275
    • 276
    • 277
    • 278
    • 279
    • 280
    • 281
    • 282
    • 283
    • 284
    • 285
    • 286
    • 287
    • 288
    • 289
    • 290
    • 291
    • 292
    • 293
    • 294
    • 295
    • 296
    • 297
    • 298
    • 299
    • 300
    • 301
    • 302
    • 303
    • 304
    • 305
    • 306
    • 307
    • 308
    • 309
    • 310
    • 311
    • 312
    • 313
    • 314
    • 315
    • 316
    • 317
    • 318
    • 319
    • 320
    • 321
    • 322
    • 323
    • 324
    • 325
    • 326
    • 327
    • 328
    • 329
    • 330
    • 331
    • 332
    • 333
    • 334
    • 335
    • 336
    • 337
    • 338
    • 339
    • 340
    • 341
    • 342
    • 343
    • 344
    • 345
    • 346
    • 347
    • 348
    • 349
    • 350
    • 351
    • 352
    • 353
    • 354
    • 355
    • 356
    • 357
    • 358
    • 359
    • 360
    • 361
    • 362
    • 363
    • 364
    • 365
    • 366
    • 367
    • 368
    • 369
    • 370
    • 371
    • 372
    • 373
    • 374
    • 375
    • 376
    • 377
    • 378
    • 379
    • 380
    • 381
    • 382
    • 383
    • 384
    • 385
    • 386
    • 387
    • 388
    • 389
    • 390
    • 391
    • 392
    • 393
    • 394
    • 395
    • 396
    • 397
    • 398
    • 399
    • 400
    • 401
    • 402
    • 403
  • 相关阅读:
    由浅入深Dubbo网络通信深入解析
    mall:redis项目源码解析
    Linux操作系统 - 进程状态
    webpack 高级
    Wireshark TS | 消失的 TCP DUP ACK
    MyBatis有哪几种运行SQL的方式呢?
    【对比Java学Kotlin】协程-创建和取消
    halcon-模板匹配算子(ncc/shape/scaled_shape)
    (附源码)计算机毕业设计SSMHY口腔门诊系统
    Breakdance评测:改变游戏规则的WordPress网站生成器
  • 原文地址:https://blog.csdn.net/qq_24433609/article/details/126688040