【Golang】reader库



// new reader返回从s读取的新reader。 
//类似bytes。新的缓冲区字符串,但更有效和不可写。
func NewReader(s string) *Reader { return &Reader{s, 0, -1} }


// A Reader implements the io.Reader, io.ReaderAt, io.ByteReader, io.ByteScanner,io.RuneReader, io.RuneScanner, io.Seeker, and io.WriterTo interfaces by reading from a string.
// The zero value for Reader operates like a Reader of an empty string.
type Reader struct {
	s        string //表示 Reader 要读取的数据源。
	i        int64 // 一个整数,表示当前读取的索引位置。
	prevRune int   // 一个整数,表示上一个读取的符文的索引位置,如果没有读取过符文,则为负数。
}

func (r *Reader) Len() int {
	if r.i >= int64(len(r.s)) {
		return 0
	}
	return int(int64(len(r.s)) - r.i)
}

// Size returns the original length of the underlying string.
// Size is the number of bytes available for reading via ReadAt.
// The returned value is always the same and is not affected by calls
// to any other method.
func (r *Reader) Size() int64 { return int64(len(r.s)) }

// Read 实现 the io.Reader 接口.
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
}

//如果当前读取索引 r.i 大于或等于字符串 r.s 的长度,说明已经到达字符串末尾,返回 0 和 io.EOF 错误,表示没有更多数据可读。
//io.go声明
//var EOF = errors.New("EOF")
//n = copy(b, r.s[r.i:]):这行代码使用 copy 函数将字符串 r.s 从当前索引 r.i 开始的部分复制到字节切片 b 中,并将实际复制的字节数赋给变量 n。

//r.i += int64(n):这行代码将当前读取索引 r.i 向前移动 n 个字节,以便下次读取时从新的位置开始。

//return:最后,方法返回读取的字节数 n 和错误 err(如果有)。

r.prevRune 字段在 strings.Reader 结构体中用于记录上一个读取的 rune(Unicode字符)的索引。这个字段在不同的方法中有不同的使用情况:

  1. 使用时机

    • 当使用 ReadRune 方法时,prevRune 字段会被使用。ReadRune 方法用于读取字符串中的下一个 rune,并返回它以及它的大小(以字节为单位)。在这种情况下,prevRune 用于记录上一个读取的 rune 的索引,以便在下一次调用 ReadRune 时能够正确地继续读取。
  2. 未使用时

    • 当使用 Read 方法时,prevRune 字段不会被使用。Read 方法用于从 strings.Reader 指向的字符串中读取数据到提供的字节切片中。由于 Read 方法是基于字节的读取,而不是基于 rune 的读取,因此不需要记录上一个读取的 rune 的索引。这就是为什么在 Read 方法的开始,prevRune 被设置为 -1,表示它在这个方法中不会被使用。

 

 使用样例

	//从字符串中读取内容
	str1Reader := strings.NewReader("hello")
	bytes,_:=io.ReadAll(str1Reader)
	print(string(bytes))

io.ReadAll

func ReadAll(r Reader) ([]byte, error) {
	b := make([]byte, 0, 512)
	for {
		n, err := r.Read(b[len(b):cap(b)])
		b = b[:len(b)+n]
		if err != nil {
			if err == EOF {
				err = nil
			}
			return b, err
		}

		if len(b) == cap(b) {
			// Add more capacity (let append pick how much).
			b = append(b, 0)[:len(b)]
		}
	}
}


//Reader使用一个借口类型 只有重载了Read方法就能调用
type Reader interface {
	Read(p []byte) (n int, err error)
}
// ReadRune implements the io.RuneReader interface.
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
}


  • func (r *Reader) ReadRune() (ch rune, size int, err error) {:这是方法的声明。ReadRune 方法返回三个值:读取的符文 ch、符文的字节大小 size 和可能的错误 err

  • if r.i >= int64(len(r.s)) {... }:这是一个条件判断,如果当前读取索引 r.i 大于或等于字符串 r.s 的长度,说明已经到达字符串末尾,返回 0、0 和 io.EOF 错误,表示没有更多数据可读。

  • r.prevRune = int(r.i):这行代码将 prevRune 设置为当前读取索引 r.i 的整数值。

  • if c := r.s[r.i]; c < utf8.RuneSelf {... }:这是一个条件判断,如果当前字符 c 的值小于 utf8.RuneSelf(即 128),说明它是一个 ASCII 字符,可以直接读取。

  • r.i++:这行代码将当前读取索引 r.i 向前移动一个字节。

  • return rune(c), 1, nil:这行代码返回读取的字符 c 作为符文,字节大小为 1,并且没有错误。

  • ch, size = utf8.DecodeRuneInString(r.s[r.i:]):如果当前字符不是 ASCII 字符,这行代码使用 utf8.DecodeRuneInString 函数从字符串 r.s 中当前索引 r.i 开始的部分解码一个符文,并将符文和字节大小分别赋给变量 ch 和 size

  • r.i += int64(size):这行代码将当前读取索引 r.i 向前移动 size 个字节,以便下次读取时从新的位置开始。

  • return ch, size, nil:最后,方法返回读取的符文 ch、字节大小 size 和没有错误。

总的来说,这个方法的作用是从字符串中读取一个 UTF-8 编码的符文,并返回符文的值、字节大小和是否发生错误。如果没有更多数据可读,它会返回 io.EOF 错误。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值