这一部分type部分的内容比较多,整个官方包看过去其实函数什么的很多,我的方法是根据函数名记作用但是不记参数,我的第一门语言是js,所以很多科班的东西理解不是很到位,有些不懂的地方就抱歉了

第一部分 函数部分

1.func Copy(dst Writer, src Reader) (written int64, err error)

// 从src缓存中拷贝到dst的writer之中,按照我的理解reader接口是让你读取的缓存,writer则是专门输出的接口
reader := strings.NewReader("我是你爸爸\n")
written, _ := io.Copy(os.Stdout, reader) //拷贝之后直接在终端输出
fmt.Println("拷贝的字节数是:", written)//拷贝的字节数是: 16  一个汉字三个字节,换行符号算一个字节
fmt.Println("len:", reader.Len())   //读取完了,剩下来的长度就是0

2.func CopyBuffer(dst Writer, src Reader, buf []byte) (written int64, err error)

// 大体作用还是拷贝,具体是什么作用还需要后续看
// 这边借用一下上面的written和reader
reader1 := strings.NewReader("hahaha\n")
buf := make([]byte, 1)
written, err := io.CopyBuffer(os.Stdout, reader1, buf)
if err != nil {
		fmt.Println(err)
}
fmt.Println("拷贝的字节数是:", written)
fmt.Println("缓存下来的数据是", buf)
// 我其实没搞懂

3.func CopyN(dst Writer, src Reader, n int64) (written int64, err error)

//copy的亲戚,只不过指定读取的字节
// On return, written == n if and only if err == nil 照我理解,返回值的written代表读取的字节数是没用的,理论上就是n,只有当错误的时候才有使用的价值
reader2 := strings.NewReader("some bitches\n")
io.CopyN(os.Stdout, reader2, 4) //终端输出some

// 比如这里我可以假设一个错误
reader3 := strings.NewReader("heha\n")
written, err = io.CopyN(os.Stdout, reader3, 6)
if err != nil {
	fmt.Println(err, written) //EOF 5
	// 上面只有5个字节,但我要读取6个,返回eof错误,并告诉我实际的读取数是5
}

4.func ReadAll(r Reader) ([]byte, error)

// 看名字就知道,这是一个全部读取
reader4 := strings.NewReader("我们是社会主义接班人")
buf1, _ := io.ReadAll(reader4)
fmt.Println("buf1:", string(buf1)) //buf1: 我们是社会主义接班人

5.func ReadAtLeast(r Reader, buf []byte, min int) (n int, err error)

// 至少读取,逻辑上说也就是这个min必须<=buf的长度,否则报错 short buffer
reader5 := strings.NewReader("we will rock you")
buf2 := make([]byte, 5)
if n, err := io.ReadAtLeast(reader5, buf2, 5); err != nil {
		fmt.Println(n, err)
}
fmt.Println("buf2", string(buf2))
// 我们来看一下,如果reader本身的长度小于这个min会出现什么错误
reader6 := strings.NewReader("abc")
buf3 := make([]byte, 6)
if n1, err := io.ReadAtLeast(reader6, buf3, 4); err != nil {
	fmt.Println(n1, err) //3 unexpected EOF 意想不到的长度不足
}

6.func ReadFull(r Reader, buf []byte) (n int, err error)

// 饱和读取,一定要读取len(buf)的长度
reader7 := strings.NewReader("abcd")
buf4 := make([]byte, 5)
_, err = io.ReadFull(reader7, buf4)
if err != nil {
	fmt.Println(err)
}
fmt.Println(string(buf4)) //abcd reader长度不够的话明显就算了,unexpected EOF但是错误还是要报的

7.func WriteString(w Writer, s string) (n int, err error)

// 很简单,将s 写入一个 writer
// golang有很多同名的函数或者方法,一般按照相关功能去区分就可以
n2, _ := io.WriteString(os.Stdout, "是我,没想到吧\n")
fmt.Println("写入n2个字符", n2) //22

8.func Pipe() (*PipeReader, *PipeWriter)

// 一个通道相关的读取写入函数
// 我觉得这个函数可能是channel的底层函数
r, w := io.Pipe()
go func() {
	// 组织一下这个writer
	fmt.Fprintln(w, "我是golang学习者")
	w.Close()
}()
if _, err = io.Copy(os.Stdout, r); err != nil {
		fmt.Println(err)
}

第二部分 struct

1.LimitedReader

1.type LimitedReader struct {
	R Reader // underlying reader
	N int64  // max bytes remaining
 }
// 明显是对读取的字节数进行了设置

func (l *LimitedReader) Read(p []byte) (n int, err error)
// 参数p应该是读取之后存放的位置
reader8 := strings.NewReader("今天就吃烤肉饭吧")

limit := io.LimitedReader{R: reader8,
	N: 6} //不这个写法的话会报错
buf5 := make([]byte, 7)
limit.Read(buf5)
fmt.Println("buf5:", string(buf5)) //今天

2.PipeWriter 

 type PipeWriter struct {
	 contains filtered or unexported fields
	 }
 该类型就是上面那个pipe函数返回的类型,和下面这个类型是相对应的,因此有些例子可以放在一起理解
 type PipeReader struct {
 	// contains filtered or unexported fields
 }
	r1, w1 := io.Pipe()
	go func() {
		w1.Write([]byte("写入w1"))
		w1.Close() //意味着这个pip不再写入
	}()
	buf6 := make([]byte, 6) //我只读取6个字节
	r1.Read(buf6)
	r1.Close() //读取六个之后我就封闭读取
	// n8, err := r1.Read(buf6)
	// if err != nil {
	// 	fmt.Println(n8, err)
	// }
	// 0 io: read/write on closed pipe  这就是是在封闭之后在读取的结果,显示不能在一个封闭的pipe读取

 3.SectionReader

type SectionReader struct {
		// contains filtered or unexported fields
	}
	// 包含read seek 和readat方法

	// func NewSectionReader(r ReaderAt, off int64, n int64) *SectionReader
	// 创建一个sectionreader r是一个有readat方法的结构体,比如普通的strings.Reader off代表从偏移量,从off的位置后开始读取,也就是
	// off不算,n表示读取几个字节,可以理解成一个容量
	// 下面是一段官网的代码
	// r := strings.NewReader("some io.Reader stream to be read\n")
	// s := io.NewSectionReader(r, 5, 17)

	// if _, err := io.Copy(os.Stdout, s); err != nil {
	// 	log.Fatal(err)
	// }
	// func (s *SectionReader) Read(p []byte) (n int, err error)
	// 很简单的读取方法,读取之后放在p缓存里面

	// func (s *SectionReader) ReadAt(p []byte, off int64) (n int, err error)
	// 很简单的偏移读取方法

	//func (s *SectionReader) Seek(offset int64, whence int) (int64, error)
	// seek方法,更灵活的偏移读取方式

	//func (s *SectionReader) Size() int64
	// 返回这个sectionreader的字节大小,注意是原始的字节大小,不是未读取的部分的大小,那个一般是len

第三部分 interface

本章的接口多是一些定义,和接口相关的函数不多,我会举一些实现改接口的官方包里面的栗子

1.ByteReader

1.type ByteReader interface {
    ReadByte() (byte, error)
	}
 例:strings包里面的 func (r *Reader) ReadByte() (byte, error)

2.ByteScanner

2.type ByteScanner interface {
	ByteReader
	UnreadByte() error
	 }
 注意这是一个接口的嵌套
 同样是strings包当中的func (r *Reader) UnreadByte() error,在下一读取的时候,返回最近一次读取的字节

3.ByteWriter

3.type ByteWriter interface {
	WriteByte(c byte) error
	}
同样是strings包当中type Builder 当中的func (b *Builder) WriteByte(c byte) error,向builder缓存之中写入一个字节

4.Closer

4.type Closer interface {
	Close() error
	 }
 暂时没找到例子,不过上面的pip函数当中有个close方法,应该就是实现的这个功能

5.WriterTo

5. type WriterTo interface {
 WriteTo(w Writer) (n int64, err error)
	}
strings包当中的func (r *Reader) WriteTo(w io.Writer) (n int64, err error)函数,将未读取的内容打印出来

6.ReadCloser

type ReadCloser interface {
	Reader
	Closer
	}
新的interface,很明显符合这个接口的reader有read和close方法,当然不会要你去写一个close函数
这个接口提供了这个函数,func NopCloser(r Reader) ReadCloser,你有reader就给你创建一个closer

7.Reader

type Reader interface {
    Read(p []byte) (n int, err error)
	 }
最基础的接口的了,比如说我们这个strings包当中的read方法,被读取的部分会存放在这个p缓存之中

// func LimitReader(r Reader, n int64) Reader 这个接口下面有这样一个很特殊的方法,因为其返回值竟然是一个Reader,尝试一下
reader9 := strings.NewReader("哈哈哈,笑死个人")
io.Copy(os.Stdout, io.LimitReader(reader9, 12))
// 就是一个将reader进行slice的方法

// func MultiReader(readers ...Reader) Reader
//既然有slice就有concat,该函数会将众多的reader整合成一个reader,例子我就不写了

func TeeReader(r Reader, w Writer) Reader,从reader当中读取的全部内容都会释放到writer之中,不会有中间的buffer
reader10 := strings.NewReader("什么情况,大清怎么亡了\n")
reader11 := io.TeeReader(reader10, os.Stdout) //重点要看一下这个返回的reader是什么
buf7 := make([]byte, 34)
reader11.Read(buf7)
fmt.Println(string(buf7)) //什么情况,大清怎么亡了,这个方法当中返回的reader11就是reader10本身,感觉是出错的时候拿来对比的

8.ReaderAt

type ReaderAt interface {
	ReadAt(p []byte, off int64) (n int, err error)
	 }
 参考strings包,reader struct的readAt方法,在我发过的文章里有,那个方法就是实现的这个借口

9.ReaderFrom

type ReaderFrom interface {
		ReadFrom(r Reader) (n int64, err error)
	 }
这个接口是包含了一个ReadFrom函数,这个函数和read差不多,也是个读取,但是有个问题,这个函数读取之后似乎没有赋值给什么缓存

10.RuneReader

type RuneReader interface {
	ReadRune() (r rune, size int, err error)
}
看一下strings包的readRune函数,每次读取一个rune,三个返回值,r是读取的rune,err是错误处理,size是这个rune反映在字节上的大小,比如中文每个字就是3

11.RuneScanner

type RuneScanner interface {
	RuneReader
	UnreadRune() error
}
跟上面相比,多了一个unreadrune函数,还是那句话,看看我写的strings包

12.Seeker

type Seeker interface {
	Seek(offset int64, whence int) (int64, error)
 }
详见我写的strings包里的type reader当中的seek方法

13.StringWriter

type StringWriter interface {
	WriteString(s string) (n int, err error)
 }
//该接口可以参考 strings包中type Builder的writeString方法

14.WriterCloser

type WriteCloser interface {
	Writer
	Closer
	}
混合接口,包含write和close方法

15.WriterSeeker

type WriteSeeker interface {
	 Writer
	Seeker
	 }
包含write和seek两个方法的接口

16.Writer

type Writer interface {
	Write(p []byte) (n int, err error)
	}
 参见strings官方包 type builder的write方法

 func MultiWriter(writers ...Writer) Writer
	r3 := strings.NewReader("some io.Reader stream to be read\n")

	var buf11, buf12 bytes.Buffer
	w3 := io.MultiWriter(&buf11, &buf12)

	if _, err := io.Copy(w3, r3); err != nil {
		log.Fatal(err)
	}

	fmt.Print(buf11.String())
	fmt.Print(buf12.String())
贴一个官网上的写法,这个MultiWriter会将多个writer整合成一个(实际上不算整合,算一个统一操作),当你在w3进行操作的时候,实际上 也是同时对buf11和buf12进行操作,对于操作多个writer是个很好的写法

17.WriterAt

type WriterAt interface {
	WriteAt(p []byte, off int64) (n int, err error)
	}
readat函数的write版本,会从off的位置开始write

18.WriterTo

type WriterTo interface {
	WriteTo(w Writer) (n int64, err error)
	}
参见 strings包type Reader中的 writeto方法

该包其实是第一部分,io包还包含ioutil和fs,当然这是后续的内容,此外该包的interface部分都可以通过strings包当中的函数进行理解

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐