Go语言中io包核心接口示例详解

目录
  • 前言
  • Reader
  • Writer
  • Closer
  • Seeker
  • 组合接口
  • 总结

前言

IO 操作是我们在编程中不可避免会遇到的,例如读写文件,Go语言的 io 包中提供了相关的接口,定义了相应的规范,不同的数据类型可以根据规范去实现相应的方法,提供更加丰富的功能。

Go 语言提倡小接口 + 接口组合的方式,来扩展程序的行为以及增加程序的灵活性。io代码包恰恰就可以作为这样的一个标杆,它可以成为我们运用这种技巧时的一个参考标准。io包中包含了大量接口,本篇文章我们就先来学习四个核心接口以及对应的接口组合。

Reader

io.Reader接口定义了 Read 方法,用于读取数据到字节数组中:

  • 入参:字节数组 p,会将数据读入到 p 中
  • 返回值:本次读取的字节数 n,以及遇到的错误 err
type Reader interface {
	Read(p []byte) (n int, err error)
}

方法功能详解

  1. 方法读取数据写入到字节数组 p 中,由于 p 是有大小的,所以一次至多读取 len(p) 个字节
  2. 方法返回读取的数据字节数 n(0 <= n <= len(p)),以及读取过程中遇到的 error
  3. 即使一次调用读取到的数据小于 len(p),也可能会占用整个字节数组 p 作为暂存空间
  4. 如果数据源的数据量小于 len(p) 个字节,方法只会读取当前可用数据,不会等待更多数据的到来

何时返回error

  1. 在成功读取了 n(n>0)个字节后,如果产生了 error 或者 读到文件末尾 (end-of-file),本次调用必须要返回读取的字节数 n,但对于err 的值,可以选择在本次直接返回 err(err!=nil),或者在下次调用的时候再返回 err (n=0, err!=nil)。常见的一个例子就是,读取到n个字节后到达文件末尾(EOF),此时可以返回 err=EOF 或者 err=nil,下次调用返回 n=0,err=EOF。
  2. 调用者需要注意,每次调用后,如果 n>0,应该先处理数据,再考虑 err 是否为 nil。因为上一点已经指出,如果读取到 n>0 个字节后遇到 error,会同时返回 n>0 和 err!=nil,此时就需要先处理数据再考虑 err。

方法实现和调用需注意

  1. 如果想要实现该方法,不推荐同时返回 n=0 和 err=nil,除非 len(p)=0
  2. 如果调用该该方法返回 n=0 和 err=nil,可以认为什么都没有发生,不能认为是读到文件末尾了(end-of-file)
  3. 实现该方法后,一定不要持有字节数组p (保留下地址做他用)

Writer

io.Writer接口定义了 Write 方法,用于写数据到文件中

  • 入参:字节数组 p,会将 p 中的数据写入到文件中
  • 返回值:成功写入完成的字节数 n,以及遇到的错误 err
type Writer interface {
	Write(p []byte) (n int, err error)
}

方法功能详解

  1. 该方法将 p 中的数据写到文件中
  2. 方法返回成功写入的字节数 n(0 <= n <= len(p)),以及写入过程中遇到的错误 err
  3. 如果 n<len(p),方法必须返回 err!=nil
  4. 方法一定不能修改字节数组 p,即使是临时修改也不被允许

方法实现需注意

实现该方法后,一定不要持有字节数组p,只是用来读取数据

Closer

io.Closer接口定义了 Close 方法,该方法用于关闭连接。

方法实现需注意

第一次调用该方法后,再次调用该方法应该产生什么行为,该接口没有定义,依赖实现方法自定义。

type Closer interface {
	Close() error
}

Seeker

io.Seeker接口定义了 Seek 方法,该方法用于指定下次读取或者写入时的偏移量

入参:计算新偏移量的起始值 whence, 基于whence的偏移量offset

返回值:基于 whence 和 offset 计算后新的偏移量值,以及可能产生的错误

type Seeker interface {
	Seek(offset int64, whence int) (int64, error)
}

方法功能详解

io包中定义了如下三种 whence

const (
	SeekStart   = 0 // 基于文件开始位置
	SeekCurrent = 1 // 基于当前偏移量
	SeekEnd     = 2 // 基于文件结束位置
)

如果计算后新的偏移量,在文件起始位置之前,返回 error!=nil

任意正数的偏移量都是合法的,但是对数据源如何进行I/O操作,依赖具体的实现方法

组合接口

在go语言中,可以利用接口的组合,来囊括其他接口中的方法,类似于定义了一个父接口,可以包含多个子接口。如果一个 struct 实现了所有子接口的方法,也就相当于实现了父接口。小接口 + 接口组合的方式,很大程度上增加了程序的灵活性,在我们自己业务开发过程中,可以借鉴这种做法。

针对上面四个最小粒度的接口,io包定义了如下几种组合接口:

// ReadWriter 是 Read 和 Write 方法的组合
type ReadWriter interface {
	Reader
	Writer
}

// ReadCloser 是 Read 和 Close 方法的组合
type ReadCloser interface {
	Reader
	Closer
}

// WriteCloser 是 Write 和 Close 方法的组合
type WriteCloser interface {
	Writer
	Closer
}

// ReadWriteCloser 是 Read、Write 和 Close 方法的组合
type ReadWriteCloser interface {
	Reader
	Writer
	Closer
}

// ReadSeeker 是 Read 和 Seek 方法的组合
type ReadSeeker interface {
	Reader
	Seeker
}

// WriteSeeker 是 Write 和 Seek 方法的组合
type WriteSeeker interface {
	Writer
	Seeker
}

// ReadWriteSeeker 是 Read、Write 和 Seek 方法的组合
type ReadWriteSeeker interface {
	Reader
	Writer
	Seeker
}

总结

本篇文章介绍了 io包 中的四大核心接口:

  • Reader : 读取文件中的数据到字节数组中
  • Writer : 将字节数组的数据写入到文件中
  • Closer : 用于关闭连接
  • Seeker : 给定 whence 和 offset,计算得出新的offset,用于在特定位置开始读写

可以看到 Reader 和 Writer 接口中定义的方法中,都有字节数组p,而底层要操作的文件在方法中都没有体现。Read方法是将文件的数据读入字节数组p,Write 是将字节数组p的数据写入文件,这一点不要记混。

到此这篇关于Go语言中io包核心接口的文章就介绍到这了,更多相关Go语言io包核心接口内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • GO语io包的常用接口

    本文实例分析了GO语io包的常用接口.分享给大家供大家参考.具体分析如下: 我没有 C/C++ 基础,没有接口的概念,且从 Python 投奔而来,Python 的极简主义(一个结果往往只提供一个方法),让我在 Golang 中非常迷糊,特别是文件的读写操作,因为 Go 的文件读写操作有很多的方法,让我不知道怎么选择.直到我学习了 interface 的概念,然后由看了 package io 后才慢慢理解,也渐渐的喜欢上了 Golang 的灵活性.以我的经验来说,接口是一个很重要的知识点,是一系

  • GO语言的IO方法实例小结

    type PipeWriter 复制代码 代码如下: type PipeWriter struct {     // contains filtered or unexported fields } (1)func (w *PipeWriter) Close() error关闭管道,关闭时正在进行的Read操作将返回EOF,若管道内仍有未读取的数据,后续仍可正常读取 复制代码 代码如下: import (  "fmt"  "io" ) func main() {  

  • Go语言中io包核心接口示例详解

    目录 前言 Reader Writer Closer Seeker 组合接口 总结 前言 IO 操作是我们在编程中不可避免会遇到的,例如读写文件,Go语言的 io 包中提供了相关的接口,定义了相应的规范,不同的数据类型可以根据规范去实现相应的方法,提供更加丰富的功能. Go 语言提倡小接口 + 接口组合的方式,来扩展程序的行为以及增加程序的灵活性.io代码包恰恰就可以作为这样的一个标杆,它可以成为我们运用这种技巧时的一个参考标准.io包中包含了大量接口,本篇文章我们就先来学习四个核心接口以及对应

  • Springboot自动扫描包路径来龙去脉示例详解

    我们暂且标注下Springboot启动过程中较为重要的逻辑方法,源码对应的spring-boot-2.2.2.RELEASE版本 public ConfigurableApplicationContext run(String... args) { StopWatch stopWatch = new StopWatch(); stopWatch.start(); ConfigurableApplicationContext context = null; Collection<SpringBoo

  • Java 语言中Object 类和System 类详解

    Object是java所有类的基类,是整个类继承结构的顶端,也是最抽象的一个类.大家天天都在使用toString().equals().hashCode().waite().notify().getClass()等方法,或许都没有意识到是Object的方法,也没有去看Object还有哪些方法以及思考为什么这些方法要放到Object中. 一.Java Object类简介-所有类的超类 Object 是 Java 类库中的一个特殊类,也是所有类的父类.也就是说,J ava 允许把任何类型的对象赋给

  • C语言中的const和free用法详解

    注意:C语言中的const和C++中的const是有区别的,而且在使用VS编译测试的时候.如果是C的话,请一定要建立一个后缀为C的文件,不要是CPP的文件.因为,两个编译器会有差别的. 一.C语言中的const比较常见的用法,const做常量 #include<stdio.h> #include<malloc.h> #include<string.h> /* C中的const用法(使用VS测试的时候,要注意建立一个C后缀的文件,因为C的编译器和C++的编译器还是有区别的

  • C语言中qsort函数的用法实例详解

    C语言中qsort函数的用法实例详解 快速排序是一种用的最多的排序算法,在C语言的标准库中也有快速排序的函数,下面说一下详细用法. qsort函数包含在<stdlib.h>中 qsort函数声明如下: void qsort(void * base,size_t nmemb,size_t size ,int(*compar)(const void *,const void *)); 参数说明: base,要排序的数组 nmemb,数组中元素的数目 size,每个数组元素占用的内存空间,可使用si

  • 在C#和Java语言中for和foreach的区别详解

    for循环和foreach循环的区别 首先在这里声明一点,C#和Java这两种语言很相似,尤其是初学的数据类型那一部分,所以这里写的for和foreach的区别在C#和Java中都适用. 我会在下面分别列出两种语言的for和foreach分别循环打印一个数组,大家可以看看区别 话不多说,直接上代码: //c# //先创建一个数组 int[] arr = new int[3] {99, 11, 22}; //利用for循环打印(可以创建一个变量 i;判断这个i是否小于数组的长度;每次循环i自增1)

  • Tomcat启动核心流程示例详解

    目录 一.Tomcat的启动核心流程 1.启动的入口 2.init方法 3.load方法 4.start方法 5.核心流程的总结 一.Tomcat的启动核心流程 前面给大家介绍了Tomcat中的生命周期的设计,掌握了这块对于我们分析Tomcat的核心流程是非常有帮助的,也就是我们需要创建相关的核心组件,比如Server,Service肯定都绕不开生命周期的方法. 1.启动的入口 你可以通过脚本来启动Tomcat服务(startup.bat),但如果你看过脚本的命令,你会发现最终调用的还是Boot

  • C语言中printf()缓冲问题详解

    前言 缓冲区又称为缓存,它是内存空间的一部分.也就是说,在内存空间中预留了一定的存储空间,这些存储空间用来缓冲输入或输出的数据,这部分预留的空间就叫做缓冲区. 缓冲区根据其对应的是输入设备还是输出设备,分为输入缓冲区和输出缓冲区. 为什么要引入缓冲区 比如我们从磁盘里取信息,我们先把读出的数据放在缓冲区,计算机再直接从缓冲区中取数据,等缓冲区的数据取完后再去磁盘中读取,这样就可以减少磁盘的读写次数,再加上计算机对缓冲区的操作大大快于对磁盘的操作,故应用缓冲区可大大提高计算机的运行速度. 又比如,

  • Go语言中map使用和并发安全详解

    目录 1 map使用 1.1 map定义 1.2 map的使用和概念 1.3 map的容量 1.4 map的使用 1.4.1 map的遍历 1.4.2 map的删除和断言 1.5 map的坑 2 并发安全 2.1 不安全原因 2.2 解决方案 总结 1 map使用 1.1 map定义 map是一种无序的集合,对应的key (索引)会对应一个value(值),所以这个结构也称为关联数组或字典. map在其他语言中hash.hash table等 var mapname map[keytype]va

  • C语言中sizeof()与strlen()的区别详解

    前言 sizeof()和strlen()经常会被初学者混淆,但其中有有很大区别: sizeof() 1. sizeof()[操作数所占空间的字节数大小]是一种c中的基本运算符. 可以以类型.指针.数组和函数等作为参数. 头文件类型为unsigned int. 运算值在编译的时候就出结果,所以可以用来定义数组维数. char a[5]="123"; int b=sizeof(a);//b=5 int c=strlen(a);//c=3 sizeof()是一种单目操作符,是用来计算你所使用

随机推荐