Go圣经-学习笔记入门bufio

cdh0805010 · · 665 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

bufio数据读取注意项

在go圣经第一章节 bufio-缓存IO,有个例子,不读源码不容易理解。

DEMO 1

func main(){
    reader :=bufio.NewReader(
    strings.NewReader(""http://studygolang.com. \nIt is the home of gophers, yes or no ?"),
    )
    
    line, _ := reader.ReadSlice('\n')
    fmt.Printf("line=%s", line) // 注意点:bufio.ReadSlice会把'\n'读取进来, 所以自带换行
    n, _ := reader.ReadSlice('\n')
    fmt.Printf("the line:%s\n", line) // 猜猜line返回结果
    fmt.Println(string(n)) // 没有读取到换行符
    return
}

打印结果:

the line:http://studygolang.com. 
the line:It is the home of gophers
It is the home of gophers, yes or no ?

DEMO 2

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
     lastRuneSize int
 }
 
func main(){
    reader :=bufio.NewReader(
    strings.NewReader(""http://studygolang.com. \nIt is the home of gophers, yes or no ?\n"),
    ) // 多加一个`\n`
    
    line, _ := reader.ReadSlice('\n')
    fmt.Printf("line=%s", line) // 注意点:bufio.ReadSlice会把'\n'读取进来, 所以自带换行
    n, _ := reader.ReadSlice('\n')
    fmt.Printf("the line:%s\n", line) // 猜猜line返回结果
    fmt.Println(string(n)) // 读取到换行符
    return
}

打印结果:

the line:http://studygolang.com. 
the line:http://studygolang.com. 

It is the home of gophers, yes or no ?

其输出结果对比,大跌眼镜,居然有无\n结果,差距这么大。

深入分析源码:

func (b *Reader) ReadSlice(delim byte) (line []byte, err error){
    for {
        if i:=bytes.IndexBytes(b.buf[b.r:b.w], delim); i>= 0{
            line = b.buf[b.r : b.r+i+1]
            b.r =i+1
            break
        }
        ...
        b.fill() // 如果buf已经读完,需要再次从b.rd中读取新的数据
    }
}

func (b *Reader) fill() {
    if b.r > 0 {
        copy(b.buf, b.buf[b.r: b:w])
        b.w -=b.r
        b.r=0
    }
    
    ...
}

以上为代码关键点,我们现在分别讨论:

  • 对于第一个DEMO,第二个line返回的是It is the home of gophers, yes or no ?,期望是返回 http://studygolang.com..
    • 分析如下:因为第二次读取reader.ReadSlice时,bytes.IndexByte没有发现第二个\n, 所以返回的索引i小于0, 则会执行fill方法,则时因为第一次读取了数据,所以b.r肯定大于0,所以执行了copy操作,buf底层数组发生了变化,变成了新写入的b.buf[b.r: b.w]值,但是要注意,line的长度和容量是不变的,所以会存在截断或者不足的情况。
  • 对于第二个DEMO,希望和期望的值是相同的
    • 分析如下:因为第二次读取reader.ReadSlice时,bytes.IndexByte可以发现第二个\n, 则直接返回,写没有修改buf底层数据,也就使得line底层数组没有发生变化。

结论:所以我们在使用标准库时,不是很明白的方法要搞清楚才能好一些,不然容易犯错误。以下是规避ReadSlice错误的方法

func (b *Reader) ReadString(delim byte) (string, error) // 安全
func (b *Reader) ReadBytes(delim byte) ([]byte, error) // 安全, 因为返回的[]byte是用make新分配内存空间

有疑问加站长微信联系(非本文作者)

本文来自:开源中国博客

感谢作者:cdh0805010

查看原文:Go圣经-学习笔记入门bufio

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

665 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传