go 学习之bufio
bufio模块通过对io模块的封装,提供了数据缓冲功能,能够一定程度减少大块数据读写带来的开销。实际上在bufio各个组件内部都维护了一个缓冲区,数据读写操作都直接通过缓存区进行。当发起一次读写操作时,会首先尝试从缓冲区获取数据;只有当缓冲区没有数据时,才会从数据源获取数据更新缓冲。
Reader
可以通过NewReader函数创建bufio.Reader对象,函数接收一个io.Reader作为参数;也就是说,bufio.Reader不能直接使用,需要绑定到某个io.Reader上。函数声明如下:
func NewReader(rd io.Reader) *Reader
func NewReaderSize(rd io.Reader, size int) *Reader // 可以配置缓冲区的大小
相较于io.Reader,bufio.Reader提供了很多实用的方法,能够更有效的对数据进行读取。首先是几个基础方法,它们能够对Reader进行细粒度的操作:
Read,读取n个byte数据
Discard,丢弃接下来n个byte数据
Peek,获取当前缓冲区内接下来的n个byte,但是不移动指针
Reset,清空整个缓冲区
具体的方法声明如下:
func (b *Reader) Read(p []byte) (n int, err error)
func (b *Reader) Discard(n int) (discarded int, err error)
func (b *Reader) Peek(n int) ([]byte, error)
func (b *Reader) Reset(r io.Reader)
除了上面的基础操作之外,bufio.Reader还提供了多个更高抽象层次的方法对数据进行简单的结构化读取。主要包括如下几个方法:
ReadByte,读取一个byte
ReadRune,读取一个utf-8字符
ReadLine,读取一行数据,由’\n’分隔
ReadBytes,读取一个byte列表
ReadString,读取一个字符串
其中前三个函数都没有参数,会从缓冲区读取一个满足需求的数据。后面两个函数接收一个参数delim,用于做数据拆分,持续读取数据直到当前字节的值等于delim,然后返回这些数据;实际上这两个函数功能相同,只是在函数返回值的类型上有所区别。具体的方法声明如下:
func (b *Reader) ReadByte() (byte, error)
func (b *Reader) ReadRune() (r rune, size int, err error)
func (b *Reader) ReadLine() (line []byte, isPrefix bool, err error)
func (b *Reader) ReadBytes(delim byte) ([]byte, error)
func (b *Reader) ReadString(delim byte) (string, error)
下面是一个简单的示例,使用ReadString方法获取用‘ ’分隔的字符串。
package main import (
"bufio"
"fmt"
"strings"
) func main() {
r := strings.NewReader("hello world !")
reader := bufio.NewReader(r) for {
str, err := reader.ReadString(byte(' '))
fmt.Println(str)
if err != nil {
return
}
}
}
Scanner
实际使用中,更推荐使用Scanner对数据进行读取,而非直接使用Reader类。Scanner可以通过splitFunc将输入数据拆分为多个token,然后依次进行读取。
和Reader类似,Scanner需要绑定到某个io.Reader上,通过NewScannner进行创建,函数声明如下:
func NewScanner(r io.Reader) *Scanner
在使用之前还需要设置splitFunc(默认为ScanLines),splitFunc用于将输入数据拆分为多个token。bufio模块提供了几个默认splitFunc,能够满足大部分场景的需求,包括:
ScanBytes,按照byte进行拆分
ScanLines,按照行(“\n”)进行拆分
ScanRunes,按照utf-8字符进行拆分
ScanWords,按照单词(” “)进行拆分
通过Scanner的Split方法,可以为Scanner指定splitFunc。使用方法如下:
scanner := bufio.NewScanner(os.StdIn)
scanner.split(bufio.ScanWords)
除此了默认的splitFunc之外,也可以定义自己的splitFunc,函数需要满足如下声明:
type SplitFunc func(data []byte, atEOF bool) (advance int, token []byte, err error)
函数接收两个参数,第一个参数是输入数据,第二个参数是一个标识位,用于标识当前数据是否为结束。函数返回三个参数,第一个是本次split操作的指针偏移;第二个是当前读取到的token;第三个是返回的错误信息。
在完成了Scanner初始化之后,通过Scan方法可以在输入中向前读取一个token,读取成功返回True;使用Text和Bytes方法获取这个token,Text返回一个字符串,Bytes返回字节数组。方法声明如下:
func (s *Scanner) Scan() bool
func (s *Scanner) Text() string
func (s *Scanner) Text() []byte
下面的示例使用Scanner对上面的示例进行了重现,可以看到和Reader相比,Scanner的使用更加便捷。
package main import (
"bufio"
"strings"
"fmt"
) func main() { scanner := bufio.NewScanner(strings.NewReader("hello world !")) scanner.Split(bufio.ScanWords) for scanner.Scan() {
fmt.Println(scanner.Text())
} }
Writer
和Reader类似,Writer也对应的提供了多组方法。基础方法包括如下几个:
func (b *Writer) Write(p []byte) (nn int, err error) // 写入n byte数据
func (b *Writer) Reset(w io.Writer) // 重置当前缓冲区
func (b *Writer) Flush() error // 清空当前缓冲区,将数据写入输出
此外,Writer也提供了多个方法方便我们进行数据写入操作:
func (b *Writer) WriteByte(c byte) error // 写入一个字节
func (b *Writer) WriteRune(r rune) (size int, err error) // 写入一个字符
func (b *Writer) WriteString(s string) (int, error) // 写入一个字符串
go 学习之bufio的更多相关文章
- Golang学习 - bufio 包
------------------------------------------------------------ // bufio 包实现了带缓存的 I/O 操作 -------------- ...
- go标准库的学习-bufio
参考https://studygolang.com/pkgdoc 导入方式: import "bufio" bufio包实现了有缓冲的I/O.它包装一个io.Reader或io.W ...
- Go语言学习包(1)之bufio包
参考网址: https://blog.csdn.net/wangshubo1989/article/details/70177928
- Beego学习笔记——Logs
日志处理 这是一个用来处理日志的库,它的设计思路来自于database/sql,目前支持的引擎有file.console.net.smtp,可以通过如下方式进行安装: go get github.co ...
- Beego学习笔记——Config
配置文件解析 这是一个用来解析文件的库,它的设计思路来自于database/sql,目前支持解析的文件格式有ini.json.xml.yaml,可以通过如下方式进行安装: go get github. ...
- Beego学习笔记——开始
beego简介 beego是一个快速开发Go应用的http框架,他可以用来快速开发API.Web.后端服务等各种应用,是一个RESTFul的框架,主要设计灵感来源于tornado.sinatra.fl ...
- Go语言学习笔记(五)文件操作
加 Golang学习 QQ群共同学习进步成家立业工作 ^-^ 群号:96933959 文件读取 os.File 封装了文件相关操作 type File File代表一个打开的文件对象. func Cr ...
- Go语言学习笔记(六)net
加 Golang学习 QQ群共同学习进步成家立业工作 ^-^ 群号:96933959 net import "net" net包提供了可移植的网络I/O接口,包括TCP/IP.UD ...
- golang学习和使用经验总结
学习网址 https://studygolang.com/pkgdoc go标准库网站 https://blog.csdn.net/sanxiaxugang/article/details/60324 ...
随机推荐
- W3C 事件切换 颜色变化
颜色变化代码: HTML: <!DOCTYPE html> <html lang="en"> <head> <meta charset=& ...
- django 多条数据显示的坑(怪自己)
今天的问题是,一个接口执行了很多次,每次都会在结果表里面记录一条结果信息,在查看接口详情页面,我想只展示一条,然后就进入误区了 第一个是怪自己手残,api_id 被自己写成app_id了 第二个是筛 ...
- DataFrame.loc的区间
df.loc[dates[0:1],'E']和df.loc[dates[0]:dates[1],'E']不同. 前者不包含dates[1],后者是包含dates[1]的. 根据Python3中实际代码 ...
- 对Promise的研究4
Promise.reject() Promise.reject(reason)方法也会返回一个新的 Promise 实例,该实例的状态为rejected. const p = Promise.reje ...
- 对logistic回归分析的两重认识
logistic回归,回归给人的直观印象只是要求解一个模型的系数,然后可以预测某个变量的回归值.而logistic回归在应用中多了一层含义,它经常应用于分类中.第一重认识:logistic是给真正的回 ...
- SQL Server查询使用键查找时锁申请及释放顺序
当然看的过程中,其实自己有个疑问: 对于键查找这类查询,会申请哪些锁,锁申请和释放的顺序是怎样的? 准备 备注:测试表仍然使用高兄文中创建的测试表testklup 在开始之前,使用dbcc ind 命 ...
- Linux内核设计与实现 总结笔记(第七章)中断和中断处理
中断和中断处理 处理器的速度跟外围硬件设备的速度往往不再一个数量级上,因此,如果内核采取让处理器向硬件发出一个请求. 然后专门等待回应的办法,如果专门等待回应,明显太慢.所以等待期间可以处理其他事务, ...
- vim 批量添加删除注释
vim中单行注释只是多行注释的一个特例,这里统一进行多行注释的讲解 (1)添加批量注释 ctrl+v 进入列编辑模式,向下或向上移动光标,把需要注释的行的开头标记起来,然后按大写的I(shift+i) ...
- Nginx 禁止IP访问 只允许域名访问
今天要在Nginx上设置禁止通过IP访问服务器,只能通过域名访问,这样做是为了避免别人把未备案的域名解析到自己的服务器IP而导致服务器被断网,从网络上搜到以下解决方案: Nginx的默认虚拟主机在用户 ...
- [NOIP2016]蚯蚓 题解
题目描述 本题中,我们将用符号[c]表示对c向下取整,例如:[3.0」= [3.1」= [3.9」=3.蛐蛐国最近蚯蚓成灾了!隔壁跳蚤国的跳蚤也拿蚯蚓们没办法,蛐蛐国王只好去请神刀手来帮他们消灭蚯蚓. ...