首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >Golang io标准库使用解析

Golang io标准库使用解析

原创
作者头像
小许code
发布2023-05-06 09:21:24
发布2023-05-06 09:21:24
7390
举报
文章被收录于专栏:小许code小许code

前言

io包提供了对I/O(input和output,即输入输出)原语的基本接口,它的基本任务是包装这些原语已有的实现(如os包里的原语),使之成为共享的公共接口。比如在 Go 语言标准库 strings、bytes、bufio、和 os 中,都有实现 io.Reader 的类型。本文我们通过IO库定义的接口,一步步加深了解。

io库定义的接口

先看IO库的代码,src/io/io.go,这里是所有io接口的定义,基础接口和组合接口,但是注意的是这是只是定义了接口语义,并不涉及到接口的具体实现,对于接口的具体实现我们会结合日常遇到的列举一些场景,这里我大概理了一下这些接口的关系,如下图:

io库接口定义
io库接口定义

图中Reader、Writer、Closer、Seeker接口是基本接口,但是组合类型接口中的ReadWriter等这些是基于这几个,利用匿名方式组合的、然后还有一些独立的接口,比如ReaderFrom。

我们先来看Reader,Reader是包装基本Read方法的接口,Read最多可将len(p)个字节读入p,它返回字节数读取(0<=n<=len(p))和遇到的任何错误。

代码语言:javascript
复制
type Reader interface {
     Read(p []byte) (n int, err error)
}

Writer是包装基本Write方法的接口,Write将len(p)个字节从p写入底层数据流,它返回从p(0<=n<=len(p))写入的字节数,以及所遇到的导致写入提前停止的任何错误,如果Write返回n<len(p),则它必须返回一个非零错误。在bytes和bufio包都有对他Wirte方法的实现,后面我会贴个图,我们可以根据列出来的结构体去查对于具IO接口的具体实现方法。

代码语言:javascript
复制
type Writer interface {
     Write(p []byte) (n int, err error)
}

比如ReadWriter就是组合类型的接口,是Reader和Writer接口利用匿名字段组合的,如果要实现ReadWriter接口就要同时实现Reader和Writer接口的方法。

代码语言:javascript
复制
type ReadWriter interface {
     Reader
     Writer
}

io接口的丰富实现

Go基于io定义的接口实现有哪些呢,看我总结的图就知道,是不是很熟悉,原来 strings、bytes、os都有很多实现。

基于io接口的实现
基于io接口的实现

创建内存Reader

bytes.NewReader和strings.NewReader都可以包裹[]byte或者string返回一个实现了所有read相关接口的Reader

代码语言:javascript
复制
// bytes包
func NewReader(b []byte) *Reader
// strings包
func NewReader(s string) *Reader

在什么场景会用到呢,比如我们发送一个Post请求,这里body就是我们的待发送数据,是一个io.Reader,

代码语言:javascript
复制
func (c *Client) Post(url string, bodyType string, body io.Reader) (resp *Response, err error)

//strings和bytes调用NewReader
http.Post("http://test.com", "text/plain", strings.NewReader("stings test"))
http.Post("http://test.com", "text/plain", bytes.NewReader([]byte("bytes test"))

os.File读取文件

Go的File文件句柄(File其实是个结构体),File 这个结构体对外实现了 Read,Write,ReadAt,WriteAt 等接口

代码语言:javascript
复制
type File struct {
  *file // os specific
}

type file struct {
  pfd        poll.FD
  name       string
  dirinfo    *dirInfo // nil unless directory being read
  appendMode bool     // whether file is opened for appending
}

我们使用os.Open或者os.OpenFile获得File结构体的指针,然后读取打开文件的内容,举个栗子:

代码语言:javascript
复制
file ,err:= os.Open("1.txt")
  if err != nil {
     return
 }
 //当函数退出时,及时关闭file句柄
 defer file.Close()  
 //返回 *Reader
 reader := bufio.NewReader(file) 
 //读到换行符就终止  
 str,err := reader.ReadString('\n')   

 //NewReader函数
 func NewReader(rd io.Reader) *Reader {
 return NewReaderSize(rd, defaultBufSize)
}

是不是感觉很熟悉,来看代码逻辑,先获得File句柄,因为File实现了IO.Reader接口,所以bufio.NewReader()可以传递file句柄,创建一个缓冲区(默认大小4096),bufio实现了ReadString接口读取缓冲区内容。

总结

Go 的 io 最最核心的是 io 库,如果要实现其中的 interface,还是要多看源码注释,除了定义的接口外,io/ioutil提供的ReadFile、ReadAll函数也是很好用的,同时希望本文能对大家理解Golang的io库有帮助!

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • io库定义的接口
  • io接口的丰富实现
    • 创建内存Reader
    • os.File读取文件
  • 总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档