GO_strings.Reader

GO_strings.Reader


type Reader struct {
	s        string
	i        int64 // 当前读取的下标
	prevRune int   // 记录读取中文时候的下标,除了ReadRune会赋值,其他赋值-1
}
  • Len():返回未读的字串长度,在下面的例子会讲到怎么变的
  • Size(): 返回len(s),永远不变

在这里插入图片描述

NewReader
// 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} }

Read

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
}

ReadAt

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&UnReadByte

ReadByte返回(byte, error)

UnReadByte把r.i–


ReadRune

读取中文字时候用

第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

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
}

Seek

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
}

WriteTo

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 : %d\n", s.Len()) //还未被读的string的长度 ===> 10

	fmt.Printf("size : %d\n", 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 : %d\n", s.Len()) //还未被读的string的长度 ===> 5

	fmt.Printf("size : %d\n", 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 : %d\n", s.Len()) //还未被读的string的长度 ===> 5

	fmt.Printf("size : %d\n", 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 : %d\n", s.Len()) //还未被读的string的长度 ===> 10

	fmt.Printf("size : %d\n", 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 : %d\n", s.Len()) //还未被读的string的长度 ===> 9

	fmt.Printf("size : %d\n", s.Size()) // 原始string长度,不会被改变的,每次调用都是一样的 ===> 10

	// UnreadByte,从r.i开始,往后退,r.i会-1
	fmt.Println("\nUnreadByte len多1,不影响任何len或size")

	_ = s.UnreadByte()

	fmt.Printf("len : %d\n", s.Len()) //还未被读的string的长度 ===> 10

	fmt.Printf("size : %d\n", 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 : %d\n", s.Len()) //还未被读的string的长度 ===> 6

	fmt.Printf("size : %d\n", 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 : %d\n", s.Len()) //还未被读的string的长度 ===> 8

	fmt.Printf("size : %d\n", 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

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值