社区微信群开通啦,扫一扫抢先加入社区官方微信群
社区微信群
type Reader struct {
s string
i int64 // 当前读取的下标
prevRune int // 记录读取中文时候的下标,除了ReadRune会赋值,其他赋值-1
}
未读
的字串长度,在下面的例子会讲到怎么变的// NewReader returns a new Reader reading from s.
// It is similar to bytes.NewBufferString but more efficient and read-only.
func NewReader(s string) *Reader { return &Reader{s, 0, -1} }
strings.Reader实现的Read方法,如果当前读取下标大于等于s的长度,表示已经读完了。反之,把i下标之后的内容拷贝给b,拷贝的长度为n。当前读取下标更新,加上n的长度。
func (r *Reader) Read(b []byte) (n int, err error) {
if r.i >= int64(len(r.s)) {
return 0, io.EOF
}
r.prevRune = -1
n = copy(b, r.s[r.i:])
r.i += int64(n)
return
}
strings.ReadAt是实现io包里面的另一个方法,指定从一个位置读取,和Read一样只不过把r.i改成off,由请求方决定。
和Read不同的是,如果读取的长度n < 长度b,则表示r.s已经读取完了,需要返回EOF这个错误,在Read里面是没有的。
另外,注意ReadAt不会修改r.i的位置。
func (r *Reader) ReadAt(b []byte, off int64) (n int, err error) {
// cannot modify state - see io.ReaderAt
if off < 0 {
return 0, errors.New("strings.Reader.ReadAt: negative offset")
}
if off >= int64(len(r.s)) {
return 0, io.EOF
}
n = copy(b, r.s[off:])
if n < len(b) {
err = io.EOF
}
return
}
ReadByte返回(byte, error)
UnReadByte把r.i–
读取中文字时候用
第6行,r.prevRune记录读取中文字的下标,不是加上这个中文字的大小
第7行判断读取的字节是不是中文字,如果不是,就只会读取1个byte,然后返回;反之,会把这个中文字节转换成可读文字返回。
r.i加上读取字节的大小。
func (r *Reader) ReadRune() (ch rune, size int, err error) {
if r.i >= int64(len(r.s)) {
r.prevRune = -1
return 0, 0, io.EOF
}
r.prevRune = int(r.i)
if c := r.s[r.i]; c < utf8.RuneSelf {
r.i++
return rune(c), 1, nil
}
ch, size = utf8.DecodeRuneInString(r.s[r.i:])
r.i += int64(size)
return
}
UnreadRune退回到上一次ReadRune的位置,上一次的位置记在r.prevRune,所以r.i直接赋值为r.prevRune。这个方法必须配合ReadRune使用,如果上一次不是ReadRune,这个方法会报错。
func (r *Reader) UnreadRune() error {
if r.i <= 0 {
return errors.New("strings.Reader.UnreadRune: at beginning of string")
}
if r.prevRune < 0 {
return errors.New("strings.Reader.UnreadRune: previous operation was not ReadRune")
}
r.i = int64(r.prevRune)
r.prevRune = -1
return nil
}
strings.Reader实现io.Seeker,指定下一次读取或者写的起始位置,直接修改r.i
func (r *Reader) Seek(offset int64, whence int) (int64, error) {
r.prevRune = -1
var abs int64
switch whence {
case io.SeekStart:
abs = offset
case io.SeekCurrent:
abs = r.i + offset
case io.SeekEnd:
abs = int64(len(r.s)) + offset
default:
return 0, errors.New("strings.Reader.Seek: invalid whence")
}
if abs < 0 {
return 0, errors.New("strings.Reader.Seek: negative position")
}
r.i = abs
return abs, nil
}
strings.Reader实现io.WriterTo,写入一个io.Writer,写入的内容,取决于r.i的位置。
如果r.i已经是r.s的长度表示已经读取完,没有字节可以用于写入,会回传size 0,但是不报错,nil。
func (r *Reader) WriteTo(w io.Writer) (n int64, err error) {
r.prevRune = -1
if r.i >= int64(len(r.s)) {
return 0, nil
}
s := r.s[r.i:]
m, err := io.WriteString(w, s)
if m > len(s) {
panic("strings.Reader.WriteTo: invalid WriteString count")
}
r.i += int64(m)
n = int64(m)
if m != len(s) && err == nil {
err = io.ErrShortWrite
}
return
}
s := strings.NewReader("abcdeabcdghij")
// a b c d e f g h i j
// 1 2 3 4 5 6 7 8 9 10
// Len作用: 返回未读的字符串长度
// Size的作用:返回字符串的长度
fmt.Printf("len : %dn", s.Len()) //还未被读的string的长度 ===> 10
fmt.Printf("size : %dn", s.Size()) // 原始string长度,不会被改变的,每次调用都是一样的 ===> 10
// Read会影响未读长度的数值,为r.i+n,n为读的长度
fmt.Println("nRead 读了5个byte之后的size和len")
buf1 := make([]byte, 5)
_, _ = s.Read(buf1)
fmt.Println("buffer read : ", string(buf1)) // ===> abcde
fmt.Printf("len : %dn", s.Len()) //还未被读的string的长度 ===> 5
fmt.Printf("size : %dn", s.Size()) // 原始string长度,不会被改变的,每次调用都是一样的 ===> 10
_, _ = s.Seek(1, io.SeekStart)
buf1 = make([]byte, 5)
_, _ = s.Read(buf1)
fmt.Println("buffer read : ", string(buf1)) // ===> abcde
fmt.Printf("len : %dn", s.Len()) //还未被读的string的长度 ===> 5
fmt.Printf("size : %dn", s.Size()) // 原始string长度,不会被改变的,每次调用都是一样的 ===> 10
// ReadAt不会影响未读长度的数值,为r.i+n,n为读的长度
s = strings.NewReader("abcdefghij")
fmt.Println("nReatAt 读了指定长度之后的字符串,不影响任何len或size")
buf2 := make([]byte, 6)
_, _ = s.ReadAt(buf2, 6)
fmt.Println("buffer read : ", string(buf2)) // ===> ghij
fmt.Printf("len : %dn", s.Len()) //还未被读的string的长度 ===> 10
fmt.Printf("size : %dn", s.Size()) // 原始string长度,不会被改变的,每次调用都是一样的 ===> 10
// ReadByte每次只读1byte,从未读的index开始,每次只返回1byte,相对应的读完之后r.i会+1
s = strings.NewReader("abcdefghij")
fmt.Println("nReadByte 只读1个byte,len修改 size不修改")
buf3, _ := s.ReadByte()
fmt.Println("buffer read : ", string(buf3)) // ===> a
fmt.Printf("len : %dn", s.Len()) //还未被读的string的长度 ===> 9
fmt.Printf("size : %dn", s.Size()) // 原始string长度,不会被改变的,每次调用都是一样的 ===> 10
// UnreadByte,从r.i开始,往后退,r.i会-1
fmt.Println("nUnreadByte len多1,不影响任何len或size")
_ = s.UnreadByte()
fmt.Printf("len : %dn", s.Len()) //还未被读的string的长度 ===> 10
fmt.Printf("size : %dn", s.Size()) // 原始string长度,不会被改变的,每次调用都是一样的 ===> 10
// Seek,算偏移,可以指定到那个index,会改变len
fmt.Println("nSeek 偏移位数,一般配合read来用")
bias, _ := s.Seek(4, io.SeekCurrent)
buf4 := make([]byte, 3)
_, _ = s.ReadAt(buf4, bias)
fmt.Println("buffer read : ", string(buf4)) // ===> efg
fmt.Printf("len : %dn", s.Len()) //还未被读的string的长度 ===> 6
fmt.Printf("size : %dn", s.Size()) // 原始string长度,不会被改变的,每次调用都是一样的 ===> 10
bias, _ = s.Seek(-2, io.SeekCurrent)
buf5 := make([]byte, 3)
_, _ = s.ReadAt(buf5, bias)
fmt.Println("buffer read : ", string(buf5)) // ===> cde
fmt.Printf("len : %dn", s.Len()) //还未被读的string的长度 ===> 8
fmt.Printf("size : %dn", s.Size()) // 原始string长度,不会被改变的,每次调用都是一样的 ===> 10
zw := strings.NewReader("测a中文")
ch, size, _ := zw.ReadRune()
fmt.Printf("buffer read : %c n", ch) // ===> 测
fmt.Println("buffer read size : ", size) // ===> 3
ch, size, _ = zw.ReadRune()
fmt.Printf("buffer read : %c n", ch) // ===> a
fmt.Println("buffer read size : ", size) // ===> 1
_ = zw.UnreadRune()
ch, size, _ = zw.ReadRune()
fmt.Printf("buffer read : %c n", ch) // ===> a
fmt.Println("buffer read size : ", size) // ===> 1
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!