golang strings.NewReader
为什么说strings.Reader类型的值可以高效地读取字符串
与strings.Builder类型恰恰相反,strings.Reader类型是为了高效读取字符串而存在的。后者的高效主要体现在它对字符串的读取机制上,它封装了很多用于在string值上读取内容的最佳实践。
strings.Reader类型的值(以下简称Reader值)可以让我们很方便地读取一个字符串中的内容。在读取的过程中,Reader值会保存已读取的字节的计数(以下简称已读计数)。
已读计数也代表着下一次读取的起始索引位置。Reader值正是依靠这样一个计数,以及针对字符串值的切片表达式,从而实现快速读取。
此外,这个已读计数也是读取回退和位置设定时的重要依据。虽然它属于Reader值的内部结构,但我们还是可以通过该值的Len方法和Size把它计算出来的
Reader值拥有的大部分用于读取的方法都会及时地更新已读计数。比如,ReadByte方法会在读取成功后将这个计数的值加1。
又比如,ReadRune方法在读取成功之后,会把被读取的字符所占用的字节数作为计数的增量。
不过,ReadAt方法算是一个例外。它既不会依据已读计数进行读取,也不会在读取后更新它。正因为如此,这个方法可以自由地读取其所属的Reader值中的任何内容。
// 示例1。 reader1 := strings.NewReader( "中文的的的SimpleNewReader returns a new Reader reading from s. " + "It is similar to bytes.NewBufferString but more efficient and read-only. ") %d\n",reader1.Size()-int64(reader1.Len())) fmt.Printf("len:%d\n",reader1.Len()) //原始字符串长度是141 by:= make([]byte,20) reader1.ReadAt(by,2) //这个方法不做计数也就是原值不变也就是len长度还是原始长度 buf1 := make([]byte, 3) //原值偏移量+3 len长度要-3 reader1.Read(buf1) fmt.Printf("len:%d value:%s\n",reader1.Len(),string(buf1))
打印结果为
len:141
len:138 value:中
除此之外,Reader值的Seek方法也会更新该值的已读计数。实际上,这个Seek方法的主要作用正是设定下一次读取的起始索引位置
offset2 := int64(17) expectedIndex := reader1.Size() - int64(reader1.Len()) + offset2 fmt.Printf("Seek with offset %d and whence %d ...\n", offset2, io.SeekCurrent) readingIndex, _ := reader1.Seek(offset2, io.SeekCurrent) fmt.Printf("The reading index in reader: %d (returned by Seek)\n", readingIndex) fmt.Printf("The reading index in reader: %d (computed by me)\n", expectedIndex)