io 包中接口的优势
package main
import (
"bytes"
"fmt"
"io"
"strings"
)
func main() {
// strings.Builder 主要用于构建字符串,实现的接口如下
builder := new(strings.Builder)
_ = interface{}(builder).(io.Writer)
_ = interface{}(builder).(io.ByteWriter)
_ = interface{}(builder).(fmt.Stringer)
// strings.Reader 主要用于读取字符串,实现的接口如下
reader := strings.NewReader("")
_ = interface{}(reader).(io.Reader)
_ = interface{}(reader).(io.ReaderAt)
_ = interface{}(reader).(io.ByteReader)
_ = interface{}(reader).(io.RuneReader)
_ = interface{}(reader).(io.Seeker)
_ = interface{}(reader).(io.ByteScanner) // io.ByteReader 的扩展接口
_ = interface{}(reader).(io.RuneScanner) // io.RuneReader 的扩展接口
_ = interface{}(reader).(io.WriterTo)
// bytes.Buffer 集读、写功能于一身,适合作为字节序列的缓冲区,实现的接口如下
buffer := bytes.NewBuffer([]byte{})
// 读相关
_ = interface{}(buffer).(io.Reader)
_ = interface{}(buffer).(io.ByteReader)
_ = interface{}(buffer).(io.RuneReader)
_ = interface{}(buffer).(io.ByteScanner)
_ = interface{}(buffer).(io.RuneScanner)
_ = interface{}(buffer).(io.WriterTo)
// 写相关
_ = interface{}(buffer).(io.Writer)
_ = interface{}(buffer).(io.ByteWriter)
_ = interface{}(buffer).(io.ReaderFrom)
// 导出相关
_ = interface{}(buffer).(fmt.Stringer)
// 实现众多接口的好处:可提高不同程序实体之间的互操作性
src := strings.NewReader(
"CopyN copies n bytes (or until an error) from src to dst." +
"It returns the number of bytes copied and " +
"the earliest error encountered while copying.")
dst := new(strings.Builder)
// 第一个参数只要实现 io.Writer 接口即可
// 第二个参数只有实现 io.Reader 接口即可
// 面向接口编程扩大了它的应用场景
written, err := io.CopyN(dst, src, 58)
if err != nil {
fmt.Printf("error: %v\n", err)
} else {
fmt.Printf("Written(%d): %q\n", written, dst.String())
}
}
io.Reader 接口的实现类型
package main
import (
"fmt"
"io"
"strings"
"sync"
"time"
)
func executeIfNoErr(err error, f func()) {
if err != nil {
fmt.Printf("error: %v\n", err)
return
}
f()
}
func main() {
comment := "Package io provides basic interfaces to I/O primitives. " +
"Its primary job is to wrap existing implementations of such primitives, " +
"such as those in package os, " +
"into shared public interfaces that abstract the functionality, " +
"plus some other related primitives."
fmt.Println("New a string reader and name it \"reader1\" ...")
reader1 := strings.NewReader(comment)
buf1 := make([]byte, 7)
n, err := reader1.Read(buf1)
var offset1, index1 int64
executeIfNoErr(err, func() {
fmt.Printf("Read(%d): %q\n", n, buf1[:n])
offset1 = int64(53)
index1, err = reader1.Seek(offset1, io.SeekCurrent)
})
executeIfNoErr(err, func() {
fmt.Printf("The new index after seeking from current with offset %d: %d\n",
offset1, index1)
n, err = reader1.Read(buf1)
})
executeIfNoErr(err, func() {
fmt.Printf("Read(%d): %q\n", n, buf1[:n])
})
fmt.Println()
// *io.LimitedReader
// 无论 Read 方法被调用多少次,总数据量会受到限制,这里为 7
reader1.Reset(comment)
num1 := int64(7)
fmt.Printf("New a limited reader with reader1 and number %d ...\n", num1)
reader2 := io.LimitReader(reader1, 7)
buf2 := make([]byte, 10)
for i := 0; i < 3; i++ {
n, err = reader2.Read(buf2)
executeIfNoErr(err, func() {
fmt.Printf("Read(%d): %q\n", n, buf2[:n])
})
}
fmt.Println()
// *io.SectionReader
// 只能够读取原始数据的某段,数据段的起始位置和末尾位置需在初始化时指明,之后无法更改
reader1.Reset(comment)
offset2 := int64(56)
num2 := int64(72)
fmt.Printf("New a section reader with reader1, offset %d and number %d ...\n", offset2, num2)
reader3 := io.NewSectionReader(reader1, offset2, num2)
buf3 := make([]byte, 20)
for i := 0; i < 5; i++ {
n, err = reader3.Read(buf3)
executeIfNoErr(err, func() {
fmt.Printf("Read(%d): %q\n", n, buf3[:n])
})
}
fmt.Println()
// *io.teeReader
// 两个参数 r 和 w,类型分别为 io.Reader 和 io.Writer
// 结果值的 Read 方法会把 r 中的数据经过作为方法参数的字节切片 p 写入到 w
reader1.Reset(comment)
writer1 := new(strings.Builder)
fmt.Println("New a tee reader with reader1 and writer1 ...")
reader4 := io.TeeReader(reader1, writer1)
buf4 := make([]byte, 40)
for i := 0; i < 8; i++ {
n, err = reader4.Read(buf4)
executeIfNoErr(err, func() {
fmt.Printf("Read(%d): %q\n", n, buf4[:n])
})
}
fmt.Println()
// io.multiReader
// MultiReader 方法可以接受若干个 io.Reader 类型的参数值
// 并返回一个实际类型为 io.multiReader 的结果值
// 当该结果值的 Read 方法被调用时,它会顺序地从前面的 io.Reader 参数中读取数据
reader5a := strings.NewReader(
"MultiReader returns a Reader that's the logical concatenation of " +
"the provided input readers.")
reader5b := strings.NewReader("They're read sequentially.")
reader5c := strings.NewReader("Once all inputs have returend EOF, Read will return EOF.")
reader5d := strings.NewReader("If any of the readers return a non-nil, " +
"non-EOF error, Read will return that error.")
fmt.Println("New a multi-reader with 4 readers ...")
reader5 := io.MultiReader(reader5a, reader5b, reader5c, reader5d)
buf5 := make([]byte, 50)
for i := 0; i < 8; i++ {
n, err = reader5.Read(buf5)
executeIfNoErr(err, func() {
fmt.Printf("Read(%d): %q\n", n, buf5[:n])
})
}
fmt.Println()
// io.pipe
// 实现了 io.Reader 接口和 io.Writer 接口
// io.Pipe() 会返回那两个类型的指针值,并分别作为内存管道的两端
fmt.Println("New a synchronous in-memory pipe ...")
pReader, pWriter := io.Pipe()
_ = interface{}(pReader).(io.ReadCloser)
_ = interface{}(pWriter).(io.WriteCloser)
comments := [][]byte{
[]byte("Pipe creates a synchronous in-memory pipe."),
[]byte("It can be used to connect code expecting an io.Reader "),
[]byte("with code expecting an io.Writer."),
}
var wg sync.WaitGroup
wg.Add(2)
go func() {
defer wg.Done()
for _, d := range comments {
time.Sleep(time.Millisecond * 500)
n, err := pWriter.Write(d)
if err != nil {
fmt.Printf("write error: %v\n", err)
break
}
fmt.Printf("Written(%d): %q\n", n, d)
}
pWriter.Close()
}()
go func() {
defer wg.Done()
wBuf := make([]byte, 55)
for {
n, err := pReader.Read(wBuf)
if err != nil {
fmt.Printf("read error: %v\n", err)
break
}
fmt.Printf("Read(%d): %q\n", n, wBuf[:n])
}
pReader.Close()
}()
wg.Wait()
}
io 包中的接口体系
|
请发表评论