当前位置 博文首页 > 魏小言的博客:源码分析之Bufio

    魏小言的博客:源码分析之Bufio

    作者:[db:作者] 时间:2021-06-24 12:40

    源码分析之Bufio

    源码路径:/usr/local/go/src/bufio

    Bufio 有缓冲区的IO,在数据批量操作上相对原生IO效率具有提高; Bufio含有三个对象【type Reader\type
    Writer\type
    ReadWriter】;三个常量【defaultBufSize\minReadBufferSize\maxConsecutiveEmptyReads】;四个全局错误变量【ErrInvalidUnreadByte\ErrInvalidUnreadRune\ErrBufferFull\ErrNegativeCount】

    三个对象之【Reader】

    type Reader struct {
        buf          []byte    //buffer area array byte.  缓冲区[]byte
        rd           io.Reader // reader provided by the client.    原生io
        r, w         int       // buf read and write positions\index.   读写下标,判断缓冲区是否可读
        err          error     // 错误产出Msg
        lastByte     int     // last byte read for UnreadByte; -1 means invalid
        lastRuneSize int     // size of last rune read for UnreadRune; -1 means invalid
    }
    Func Read
    当读取目的数组字段为空时,返回0+读取状态;
        当缓冲区为空&&目的字段长度大于\等于缓冲区时,直接从原生io中读取;
        当缓冲区为空&&目的字段长度小于缓冲区时,原生io读至缓冲区;
            读取缓冲区至目的数组;
    func (b *Reader) Read(p []byte) (n int, err error) {
        n = len(p)
        if n == 0 {
            if b.Buffered() > 0 {
                return 0, nil
            }
            return 0, b.readErr()
        }
        if b.r == b.w {
            if b.err != nil {
                return 0, b.readErr()
            }
            if len(p) >= len(b.buf) {
                // Large read, empty buffer.
                // Read directly into p to avoid copy.
                n, b.err = b.rd.Read(p)
                if n < 0 {
                    panic(errNegativeRead)
                }
                if n > 0 {
                    b.lastByte = int(p[n-1])
                    b.lastRuneSize = -1
                }
                return n, b.readErr()
            }
            // One read.
            // Do not use b.fill, which will loop.
            b.r = 0
            b.w = 0
            n, b.err = b.rd.Read(b.buf)
            if n < 0 {
                panic(errNegativeRead)
            }
            if n == 0 {
                return 0, b.readErr()
            }
            b.w += n
        }
        // copy as much as we can
        n = copy(p, b.buf[b.r:b.w])
        b.r += n
        b.lastByte = int(b.buf[b.r-1])
        b.lastRuneSize = -1
        return n, nil
    }
    

    另注:【copy原、目的Size差异场景】

    // The copy built-in function copies elements from a source slice into a
    // destination slice. (As a special case, it also will copy bytes from a
    // string to a slice of bytes.) The source and destination may overlap. Copy
    // returns the number of elements copied, which will be the minimum of
    // len(src) and len(dst).
    func copy(dst, src []Type) int
    Func ReadBytes
    ReadBytes 在 b 中查找 delim 并读出 delim 及其之前的所有数据
     如果 ReadBytes 在找到 delim 之前遇到错误
     则返回遇到错误之前的所有数据,同时返回遇到的错误(通常是 io.EOF)
     只有当 ReadBytes 找不到 delim 时,err 才不为 nil
     对于简单的用途,使用 Scanner 可能更方便
    func (b *Reader) ReadBytes(delim byte) (line []byte, err error)
    Func ReadLine
     ReadLine 是一个低级的原始的行读取操作
     大多数情况下,应该使用 ReadBytes('\n')ReadString('\n')
     或者使用一个 Scanner
    ReadLine 通过调用 ReadSlice 方法实现,返回的也是缓存的切片
    ReadLine 尝试返回一个单行数据,不包括行尾标记(\n 或 \r\n)
     如果在缓存中找不到行尾标记,则设置 isPrefix 为 true,表示查找未完成
     同时读出缓存中的数据并作为切片返回
     只有在当前缓存中找到行尾标记,才将 isPrefix 设置为 false,表示查找完成
    可以多次调用 ReadLine 来读出一行
     返回的数据在下一次读取操作之前是有效的
     如果 ReadLine 无法获取任何数据,则返回一个错误信息(通常是 io.EOF)
    func (b *Reader) ReadLine() (line []byte, isPrefix bool, err error)
    Func ReadSlice
     ReadSlice 在 b 中查找 delim 并返回 delim 及其之前的所有数据的切片
     该操作会读出数据,返回的切片是已读出数据的引用
     切片中的数据在下一次读取操作之前是有效的
     如果 ReadSlice 在找到 delim 之前遇到错误
     则读出缓存中的所有数据并返回,同时返回遇到的错误(通常是 io.EOF)
     如果在整个缓存中都找不到 delim,则 err 返回 ErrBufferFull
     如果 ReadSlice 能找到 delim,则 err 始终返回 nil
     因为返回的切片中的数据有可能被下一次读写操作修改
     因此大多数操作应该使用 ReadBytes 或 ReadString,它们返回的不是数据引用
    func (b *Reader) ReadSlice(delim byte) (line []byte, err error)
    Func ReadRune\Peek\…
    …...
    
    三个对象之【Writer】
    type Writer struct {
       err   error
       buf  []byte
       n     int
       wr   io.Writer
    }
    Func Write
    Write方法首先会判断写入的数据长度是否大于设置的缓冲长度,如果小于,则会将数据copy到缓冲中;当数据长度大于缓冲长度时,如果数据特别大,则会跳过copy环节,直接写入文件。其他情况依然先会将数据拷贝到缓冲队列中,然后再将缓冲中的数据写入到文件中。
    // Write writes the contents of p into the buffer.
    // It returns the number of bytes written.
    // If nn < len(p), it also returns an error explaining
    // why the write is short.
    func (b *Writer) Write(p []byte) (nn int, err error) {
        for len(p) > b.Available() && b.err == nil {
            var n int
            if b.Buffered() == 0 {
                // Large write, empty buffer.
                // Write directly from p to avoid copy.
                n, b.err = b.wr.Write(p)
            } else {
                n = copy(b.buf[b.n:], p)
                b.n += n
                b.Flush()
            }
            nn += n
            p = p[n:]
        }
        if b.err != nil {
            return nn, b.err
        }
        n := copy(b.buf[b.n:], p)
        b.n += n
        nn += n
        return nn, nil
    }
    Func NewWriterSize
    // NewWriterSize returns a new Writer whose buffer has at least the specified
    // size. If the argument io.Writer is already a Writer with large enough
    // size, it returns the underlying Writer.
    func NewWriterSize(w io.Writer, size int) *Writer {
        // Is it already a Writer?
        b, ok := w.(*Writer)
        if ok && len(b.buf) >= size {
            return b
        }
        if size <= 0 {
            size = defaultBufSize
        }
        return &Writer{
            buf: make([]byte, size),
            wr:  w,
        }
    }
    Flush 将缓存中的数据提交到底层的 io.Writer 中
    func (b *Writer) Flush() error
    Available 返回缓存中的可以空间
    func (b *Writer) Available() int
     Buffered 返回缓存中未提交的数据长度
    func (b *Writer) Buffered() int
     Write 将 p 中的数据写入 b 中,返回写入的字节数
     如果写入的字节数小于 p 的长度,则返回一个错误信息
    func (b *Writer) Write(p []byte) (nn int, err error)
     WriteString 同 Write,只不过写入的是字符串
    func (b *Writer) WriteString(s string) (int, error)
    
    下一篇:没有了