Go圣经-学习笔记入门bufio


声明:本文转载自https://my.oschina.net/u/3287304/blog/1554101,转载目的在于传递更多信息,仅供学习交流之用。如有侵权行为,请联系我,我会及时删除。

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新分配内存空间 

本文发表于2017年10月20日 22:34
(c)注:本文转载自https://my.oschina.net/u/3287304/blog/1554101,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。如有侵权行为,请联系我们,我们会及时删除.

阅读 2010 讨论 0 喜欢 0

抢先体验

扫码体验
趣味小程序
文字表情生成器

闪念胶囊

你要过得好哇,这样我才能恨你啊,你要是过得不好,我都不知道该恨你还是拥抱你啊。

直抵黄龙府,与诸君痛饮尔。

那时陪伴我的人啊,你们如今在何方。

不出意外的话,我们再也不会见了,祝你前程似锦。

这世界真好,吃野东西也要留出这条命来看看

快捷链接
网站地图
提交友链
Copyright © 2016 - 2021 Cion.
All Rights Reserved.
京ICP备2021004668号-1