• 标准库之bufio


    1、概述

    bufio 包实现了缓存IO。它包装了 io.Reader 和 io.Writer 对象,创建了另外的Reader和Writer对象,它们也实现了 io.Reader 和 io.Writer 接口,不过它们是有缓存的。该包同时为文本I/O提供了一些便利操作。

    2、Reader 类型和方法

    bufio.Reader 结构包装了一个 io.Reader 对象,提供缓存功能,同时实现了 io.Reader 接口。

    Reader 结构没有任何导出的字段,结构定义如下:

        type Reader struct {
            buf          []byte        // 缓存
            rd           io.Reader    // 底层的io.Reader
            // r:从buf中读走的字节(偏移);w:buf中填充内容的偏移;
            // w - r 是buf中可被读的长度(缓存数据的大小),也是Buffered()方法的返回值
            r, w         int
            err          error        // 读过程中遇到的错误
            lastByte     int        // 最后一次读到的字节(ReadByte/UnreadByte)
            lastRuneSize int        // 最后一次读到的Rune的大小 (ReadRune/UnreadRune)
        }
    

    2.1、实例化 bufio.Reader 

    bufio 包提供了两个实例化 bufio.Reader 对象的函数:NewReader 和 NewReaderSize。其中,NewReader 函数是调用 NewReaderSize 函数实现的:

        func NewReader(rd io.Reader) *Reader {
            // 默认缓存大小:defaultBufSize=4096
            return NewReaderSize(rd, defaultBufSize)
        }
    

    NewReaderSize的源码:

        func NewReaderSize(rd io.Reader, size int) *Reader {
            // 已经是bufio.Reader类型,且缓存大小不小于 size,则直接返回
            b, ok := rd.(*Reader)
            if ok && len(b.buf) >= size {
                return b
            }
            // 缓存大小不会小于 minReadBufferSize (16字节)
            if size < minReadBufferSize {
                size = minReadBufferSize
            }
            // 构造一个bufio.Reader实例
            return &Reader{
                buf:          make([]byte, size),
                rd:           rd,
                lastByte:     -1,
                lastRuneSize: -1,
            }
        }
    

    2.2、ReadSlice、ReadBytes、ReadString 和 ReadLine 方法

    参考:bufio — 缓存 IO · Go语言标准库 (studygolang.com)

      2.3、Peek方法

    从方法的名称可以猜到,该方法只是“窥探”一下 Reader 中没有读取的 n 个字节。好比栈数据结构中的取栈顶元素,但不出栈。

    方法的签名如下:

    func (b *Reader) Peek(n int) ([]byte, error)
    

    同上面介绍的 ReadSlice一样,返回的 []byte 只是 buffer 中的引用,在下次IO操作后会无效,可见该方法(以及ReadSlice这样的,返回buffer引用的方法)对多 goroutine 是不安全的,也就是在多并发环境下,不能依赖其结果。

      2.4其他方法

        func (b *Reader) Read(p []byte) (n int, err error)
        func (b *Reader) ReadByte() (c byte, err error)
        func (b *Reader) ReadRune() (r rune, size int, err error)
        func (b *Reader) UnreadByte() error
        func (b *Reader) UnreadRune() error
        func (b *Reader) WriteTo(w io.Writer) (n int64, err error)
    

    3、Scanner 类型和方法

    在 bufio 包中有多种方式获取文本输入,ReadBytes、ReadString 和独特的 ReadLine,对于简单的目的这些都有些过于复杂了。在 Go 1.1 中,添加了一个新类型,Scanner,以便更容易的处理如按行读取输入序列或空格分隔单词等,这类简单的任务。它终结了如输入一个很长的有问题的行这样的输入错误,并且提供了简单的默认行为:基于行的输入,每行都剔除分隔标识。

    3.1、Scanner 的实例化

    Scanner 没有导出任何字段,而它需要有外部的 io.Reader 对象,因此,我们不能直接实例化 Scanner 对象,必须通过 bufio 包提供的实例化函数来实例化。实例化函数签名以及内部实现:

        func NewScanner(r io.Reader) *Scanner {
            return &Scanner{
                r:            r,
                split:        ScanLines,
                maxTokenSize: MaxScanTokenSize,
                buf:          make([]byte, 4096), // Plausible starting size; needn't be large.
            }
        }
    

      3.2、Scanner 的Split 方法

    Split 方法 前面我们提到过可以通过 Split 方法为 Scanner 实例设置分词行为。由于 Scanner 实例的默认 split 总是 ScanLines,如果我们想要用其他的 split,可以通过 Split 方法做到。

    比如,我们想要统计一段英文有多少个单词(不排除重复),我们可以这么做:

        const input = "This is The Golang Standard Library.\nWelcome you!"
        scanner := bufio.NewScanner(strings.NewReader(input))
        scanner.Split(bufio.ScanWords)
        count := 0
        for scanner.Scan() {
            count++
        }
        if err := scanner.Err(); err != nil {
            fmt.Fprintln(os.Stderr, "reading input:", err)
        }
        fmt.Println(count)
    

    4、Writer 类型和方法

    bufio.Writer 结构包装了一个 io.Writer 对象,提供缓存功能,同时实现了 io.Writer 接口。

    Writer 结构没有任何导出的字段,结构定义如下:

        type Writer struct {
            err error        // 写过程中遇到的错误
            buf []byte        // 缓存
            n   int            // 当前缓存中的字节数
            wr  io.Writer    // 底层的 io.Writer 对象
        }
    

      4.1实例化

    和 Reader 类型一样,bufio 包提供了两个实例化 bufio.Writer 对象的函数:NewWriter 和 NewWriterSize。其中,NewWriter 函数是调用 NewWriterSize 函数实现的:

        func NewWriter(wr io.Writer) *Writer {
            // 默认缓存大小:defaultBufSize=4096
            return NewWriterSize(wr, defaultBufSize)
        }
    

     NewWriterSize 的源码:

        func NewWriterSize(wr io.Writer, size int) *Writer {
            // 已经是 bufio.Writer 类型,且缓存大小不小于 size,则直接返回
            b, ok := wr.(*Writer)
            if ok && len(b.buf) >= size {
                return b
            }
            if size <= 0 {
                size = defaultBufSize
            }
            return &Writer{
                buf: make([]byte, size),
                wr:  w,
            }
        }
    

    4.2Available 和 Buffered 方法

    Available 方法获取缓存中还未使用的字节数(缓存大小 - 字段 n 的值);Buffered 方法获取写入当前缓存中的字节数(字段 n 的值)。

      4.3Flush 方法

    该方法将缓存中的所有数据写入底层的 io.Writer 对象中。使用 bufio.Writer 时,在所有的 Write 操作完成之后,应该调用 Flush 方法使得缓存都写入 io.Writer 对象中。

      4.4其他方法

        // 实现了 io.ReaderFrom 接口
        func (b *Writer) ReadFrom(r io.Reader) (n int64, err error)
    
        // 实现了 io.Writer 接口
        func (b *Writer) Write(p []byte) (nn int, err error)
    
        // 实现了 io.ByteWriter 接口
        func (b *Writer) WriteByte(c byte) error
    
        // io 中没有该方法的接口,它用于写入单个 Unicode 码点,返回写入的字节数(码点占用的字节),内部实现会根据当前 rune 的范围调用 WriteByte 或 WriteString
        func (b *Writer) WriteRune(r rune) (size int, err error)
    
        // 写入字符串,如果返回写入的字节数比 len(s) 小,返回的error会解释原因
        func (b *Writer) WriteString(s string) (int, error)
    

    5、ReadWriter 类型和实例化

    ReadWriter 结构存储了 bufio.Reader 和 bufio.Writer 类型的指针(内嵌),它实现了 io.ReadWriter 结构。

        type ReadWriter struct {
            *Reader
            *Writer
        }
    

    ReadWriter 的实例化可以跟普通结构类型一样,也可以通过调用 bufio.NewReadWriter 函数来实现:只是简单的实例化 ReadWriter。

        func NewReadWriter(r *Reader, w *Writer) *ReadWriter {
            return &ReadWriter{r, w}
        }
    

      

    参考:bufio — 缓存 IO · Go语言标准库 (studygolang.com)

  • 相关阅读:
    Best Time to Buy and Sell Stock III
    Valid Palindrome
    Longest Substring Without Repeating Characters
    Copy List with Random Pointer
    Add Two Numbers
    Recover Binary Search Tree
    Anagrams
    ZigZag Conversion
    Merge k Sorted Lists
    Distinct Subsequences
  • 原文地址:https://www.cnblogs.com/mango1997/p/16305935.html
Copyright © 2020-2023  润新知