源码分析之Bufio
Posted 魏小言
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了源码分析之Bufio相关的知识,希望对你有一定的参考价值。
源码分析之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)
以上是关于源码分析之Bufio的主要内容,如果未能解决你的问题,请参考以下文章
Android 逆向整体加固脱壳 ( DEX 优化流程分析 | DexPrepare.cpp 中 dvmOptimizeDexFile() 方法分析 | /bin/dexopt 源码分析 )(代码片段
Android 事件分发事件分发源码分析 ( Activity 中各层级的事件传递 | Activity -> PhoneWindow -> DecorView -> ViewGroup )(代码片段