golang标准库io相关操作解读

作为一个golang新手,对go的读写相关的操作一直都没有理解透彻,尤其是很多的方法都需要传入一个read或者write的操作,对于这种一直都不理解,而且对于读写也是不太会使用。所以希望通过自己整理标准库io相关的的数据来帮助自己理解这方面的知识。

下面开始正文

        首先,io操作,或者io流,其实也就是读写操作和读写流,就是对数据的读或者写,都可以称之为io操作。

        在官方解释中我们可以看到,使用者不能默认io包的操作时并发安全的,因为go在实际开发过程中会有很多的并发情况,而且go也是因高并发著名,所以在任何的操作我们都应当考虑是否需要并发安全性。

        在开始讲解包内容之前我们需要知道一个错误,也就是EOF,end of file 的缩写意思是文件结尾。这个错误是用来提醒使用者读取到了文件的结尾,并不是出现了错误,会经常用到。

首先来看reader

type Reader

type Reader interface{
    Read(p []byte)(n int,err error)
}

我们可以看到这是一个interface,也就是一个接口类型,是没办法直接使用,这个接口里面实现了read方法,当你定义了一个结构体,而这个结构体实现了一个read方法,那么你写的结构体是不是也实现了Reader这个接口呢?

所以这个接口是给外部实现使用的,比如我们了解的os操作,我们打开一个文件之后,是不是返回的有一个os.File类型的数据,而这个数据就有read方法去读数据,原因就是它实现了基本的Reader接口。下面用代码来接收一下吧

import (
	"IMproject/webgin"
	"fmt"
	"io"
	"log"
	"os"
)

func main() {
	f, err := os.Open("a.txt")
	if err != nil {
		log.Fatal(err)
	}
	defer f.Close()	//文件使用完成后一定要记得关闭文件,在实际的开发中会经常有文件相关的操作,如果不及时的关闭文件会造成资源的浪费,严重了会发生事故。
	
	buf:=make([]byte,100)//实例化出一个缓冲区,因为read方法需要传入一个这样的参数
	//不知道文件的大小所以要循环从文件中读取数据
	for{
		n,err:=f.Read(buf)
		if err != nil&&err!=io.EOF {
			fmt.Printf("read err:%v",err)
		}
		if n==0||err==io.EOF{
			fmt.Println("文件读取完毕")
			break
		}
		fmt.Println(string(buf[:n]))
	}
	
	
}

type Writer

type Writer interface{
        Write(p []byte)(n int , err error)

}

同样的道理,Writer接口也是同样给外部实现提供的,所以如果有结构体存在这个方法,也就实现了这个接口。这里就不过多的解释了。

        关于每个方法的具体使用请移步到官方的中文文档,百度直接搜就行。

相信到这里应该都能够理解官方文档中的所有接口了,这些并不是给外部调用的,所以,我们也没有必要去调用这些内容,需要的时候去实现就行了。我这里偷个懒就不去每个都去做解释了。

下面解释结构体

结构体大家都很熟悉,我们定义结构体时,很多情况下都是为了给他加上一些方法。标准库中亦是如此。

举例说明

type LimiteReader stuct{
R Reader

N int64

}

该结构体实现了一个Read方法

func (l *LimitedReader) Read(p []byte) (n int, err error)

作用是限制了读取的大小是N个字节,实际上是对P取0到N的切片,然后将结果传给R。如果P的大小没有这么大,就会从新设置N,也就是剩余可以使用的字节大小。这个可以去源码中看,还是比较简单的。

另外获取LimiteReader结构体可以使用如下函数

func LimitReader(r Reader, n int64) Reader { return &LimitedReader{r, n} }

它会返回一个LimiteReader结构体。

供外部调用的函数

我们多数也是使用io包提供的一下函数,但是理解上面的都是也是很很重要的。理解了上面的内容之后,你就能够更好的理解,io包提供的函数是怎么回事了。写到这里我就大致的明白其他的一些函数中的reader、writer参数了。也就是实现了Reader、Writer接口的结构体罢了。

搞明白这些之后剩下的函数就没有必要每个都去写一下了。我写这个博客的目的也是帮助自己梳理逻辑,所以并不会有太多实际的内容。能不能帮助到读者就看我们是不是有相同的问题了。

推荐一个博客,具体io标准库可以去这里看:https://blog.csdn.net/qq_39280718/article/details/125704311

写的非常的好。

io/ioutil

这个包对io包中的方法做了进一步的封装,封装了一下os操作,比如从文件中读写的操作,就是封装了打开和关闭文件,这些都是os操作,这个包中的方法也是经常使用的。这里不做讲解,主要是没啥可讲的,记住怎么用就行了,上面讲的理解了,这些就只是一些操作。

bufio

该包的使用,首先你需要先定义出一个带有缓冲区的Reader或者Writer,你可以使用它提供的相关new方法获得相应的结构体,然后再使用结构体对应的方法。

func NewReader(rd io.Reader) *Reader
func NewReaderSize(rd io.Reader, size int) *Reader
func NewWriter(w io.Writer) *Writer
func NewWriterSize(w io.Writer, size int) *Writer
func NewReadWriter(r *Reader, w *Writer) *ReadWriter

分别是:得到默认缓冲区大小的reader

                得到指定缓冲区大小的reader

                得到默认缓冲区大小的writer

                得到指定缓冲区大小的writer

                得到默认缓冲区大小的readwriter

这几种方法都需要传入io的reader或者writer,到这又该纳闷了?这里的参数哪里来啊?你是不是也是这么想的啊?我是这么想的。

其实,bufio中的结构体是包装了io中的read,writer类,我们上面说了只要结构体实现了io中的Read,Write方法,就实现了对应的接口。其实也就可以认为是一类数据了。也就可以当做相同类型的参数传递了。

举例说明:

func test() {
	reader := strings.NewReader("abcdefg") //返回strings.reader结构体,点进源码可以看到实现了Read方法。所以可以认为是io.Reader去传参
	buf_reader := bufio.NewReader(reader)
	str, _ := buf_reader.ReadString('\n')
	fmt.Println(str)

}

到这里大概也能梳理好io,ioutil,bufio之间的关系了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值