最近写开源代码的时候被bufio的特性坑惨了 特写此篇文章记录一下
一是文件指针问题
二是跨越缓存区的\r\n问题
一.bufio.Reader的基本流程
1.文件指针问题
如图 此时我们读取了缓存区
那么fp已经在缓存区之后了 就像现在redisshake rdb的源码一样
UpdateRDBSentSize := func() {
offset, err := ld.fp.Seek(0, io.SeekCurrent)
if err != nil {
log.PanicError(err)
}
statistics.UpdateRDBSentSize(uint64(offset))
}
我们现在要通过对文件指针的seek 获得目前文件指针的位置 以此来统计文件发送的大小
但是无论你在读取过程哪时候调用 这个功能 fp都是在缓存区之后了
比如我正在读缓存区 第一个字节 此时调用这个功能 得到的也是缓存区之后 所以绝对是有误差的、
误差是一个缓存区之内 默认是4K 如果不考虑4K的误差 就没什么问题
但是像redisshake读取rdb 如果我rdb开启了校验和(8字节) 校验和是在EOF之后
但redisshake在EOF就结束 我们就当缓存区已经把校验和读了吧毕竟8字节
case kEOF:
return
那我此时用fp.seek 那算到的位置就是在文件末尾 而不是KEOF的位置 是肯定有误差的
但是应该是不考虑这个小误差 貌似redisshake也不 处理校验和
2.跨越缓存区的\r\n问题
redis的AOF为了支持跨版本
默认每行 结束后添上\r\n
但是我自己写go语言bufio读取的时候 却发现每次多读\r\n但是却会出错
后来发现每次出问题都是在缓存区的末尾 如果在用bufio读取 但是末尾是\r它是不会去 文件里面再去拿\n(我在linux上调用的代码)
为了解决 该问题 我用上了io库的readline函数
他会跳过\r\n 就不用考虑这一行的\r\n