广告
返回顶部
首页 > 资讯 > 后端开发 > GO >GOLang IO接口与工具使用方法讲解
  • 334
分享到

GOLang IO接口与工具使用方法讲解

GO IO接口GO工具 2023-03-19 17:03:00 334人浏览 泡泡鱼
摘要

目录一、io包中接口的好处和优势1.1拷贝数据的函数二、在io包中io.Reader的扩展接口和实现类型2.1 io.Reader的扩展接口2.2 io.Reader接口的实现类型2

一、io包中接口的好处和优势

1.1拷贝数据的函数

io.Copy(dst Writer, src Reader)

io.CopyBuffer(dst Writer, src Reader, buf []byte)

io.CopyN(dst Writer, src Reader, buf []byte)

	src := strings.NewReader(
		"CopyN copies n bytes (or unil an error) from src to dst." +
			"It returns the number of bytes copied and " +
			"the earliest error encountered while copying")
	dst := new(strings.Builder)
	written, err := io.CopyN(dst, src, 58)
	if err != nil {
		fmt.Printf("err: %v\n", err)
	} else {
		// Written(58): "CopyN copies n bytes (or unil an error) from src to dst.It"
		fmt.Printf("Written(%d): %q\n", written, dst.String())
	}

二、在io包中io.Reader的扩展接口和实现类型

2.1 io.Reader的扩展接口

io.ReadWriter 这个接口即是io.Reader的扩展接口,也是io.Writer的扩展接口;

该接口定义了一组行为,包含且仅包含了基本的字节序列读取方法Read,和字节写入方法Write。

io.ReadCloser: 该接口除了包含基本的字节序列读取方法以外,还拥有一个基本的关闭方法Close。

Close方法一般用于关闭数据读写的通道。这个接口其实是io.Reader接口和io.Closer接口的组合。

io.ReadWriteCloser:这个接口是io.Readerio.Writerio.Closer三个接口的组合。

io.ReadSeeker :该接口拥有一个寻找读写位置的基本方法Seek。

该方法可以根据给定的偏移量,基于数据的起始位置、末尾位置、或者当前读写位置去寻找新的读写位置。这个新的读写位置用于表明下一次读或写时的起始索引

Seek是io.Seeker接口唯一拥有的方法。

io.ReadWriteSeeker:这个接口是io.Readerio.Writerio.Seeker三个接口的组合。

2.2 io.Reader接口的实现类型

*io.LimitedReader:此类型的基本类型会包装io.Reader类型的值,并提供一个额外的受限读取的功能。

该类型的读取方法Read返回的总数据量会受到限制。无论该方法被调用多少次。这个限制由该类型的字段N指明,单位是字节。

*io.SectionReader :此类型的基本类型可以包装io.ReaderAt类型的值,并且会限制它的Read方法,只能读取原始数据的一部分(或者说某一段)。

这个数据段段起始位置和末尾位置,需要在它被初始化的时候就指明,并且之后无法变更。该类型的值的行为与切片有些类型,只会对外暴露在其窗口之中的那些数据。

*io.teeReader:该类型是一个包级私有的数据类型,也是io.TeeReader函数结果值的实际类型。

TeeReader(r Reader, w Writer)函数的结果值的Read方法,会把r中的数据经过作为方法参数的字节切片p写入w中。也就是说,p是r和w的数据搬运工。

	teeReader1 := io.TeeReader(src, dst)
	p := make([]byte, 7)
	teeReader1.Read(p)

*io.multiReader:该类型也是包级私有的数据类型。类似地,io包中有一个名为MultiReader的函数,它可以接受若干个io.Reader类型的参数值,并返回一个实际类型为io.multiReader的结果值。

当这个结果值当Read方法被调用,它会顺序地从前面那些io.Reader类型的参数值中读取数据。因此,我们也称之为多对象读取器。

*io.pipe:此类型是一个包级私有的数据类型。它不但实现了io.Reader接口,而且还实现了io.Writer接口。

实际上,io.PipeReader类型和io.PipeWriter类型拥有的所有指针方法都是以它为基础的。这些方法都是代理了io.pipe类型值所拥有的某一个方法而已。

Pipe() (*PipeReader, *PipeWriter) 返回两个类型的指针值,并分别把它们作为其生成的同步内存管道的两端。所以可以说,*io.pipe类型就是io包提供的同步内存管道的核心实现。

*ip.PipeReader该类型可以被视为*io.pipe类型的代理类型。它代理了后者的一部分功能,并基于后者实现了io.ReadClosed接口。同时,它还定义了同步内存管道的读取端。

在实际的面试中,只要应聘者能够从某一个方面出发,说出io.Reader的扩展接口及其存在意义,或者说清楚该接口的三五个实现类型,那么就可以算是基本回答正确了。

2.3 示例

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 example1(comment string) {
	// 创建一个字符串
	// 创建一个字符串读取器,它的名字是 reader1。
	fmt.Println("创建一个字符串读取器,它的名字是 reader1。")
	reader1 := strings.NewReader(comment)
	buf1 := make([]byte, 7)
	n, err := reader1.Read(buf1)
	var index1, offset1 int64
	executeIfNoErr(err, func() {
		// Read(7): "Package"
		fmt.Printf("Read(%d): %q\n", n, buf1[:n])
		offset1 = int64(54)
		index1, err = reader1.Seek(offset1, io.SeekCurrent)
	})
	executeIfNoErr(err, func() {
		fmt.Printf("基于当前的所以,移动%d的偏移量后,新的索引值为: %d \n", offset1, index1)
		n, err = reader1.Read(buf1)
	})
	executeIfNoErr(err, func() {
		fmt.Printf("Read(%d):%q\n", n, buf1[:n])
	})
	fmt.Println()
}
func example2(comment string) {
	reader1 := strings.NewReader(comment)
	reader1.Reset(comment)
	num := int64(7)
	fmt.Printf("创建一个新的限制Reader,限制读的数量为:%d\n", num)
	reader2 := io.LimitReader(reader1, num)
	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()
}
func example3(comment string) {
	reader1 := strings.NewReader(comment)
	writer1 := new(strings.Builder)
	fmt.Println("创建一个新的teeReader, 带有一个reader和一个writer")
	reader3 := io.TeeReader(reader1, writer1)
	buf4 := make([]byte, 40)
	for i := 0; i < 8; i++ {
		n, err := reader3.Read(buf4)
		executeIfNoErr(err, func() {
			fmt.Printf("Read(%d):%q\n", n, buf4[:n])
		})
	}
	fmt.Println()
}
func example4(comment string) {
	reader1 := strings.NewReader(comment)
	offset1 := int64(56)
	num2 := int64(72)
	fmt.Printf("创建一个section Reader 带有一个Reader, 偏移量为%d, 数量为 %d...\n", offset1, num2)
	reader2 := io.NewSectionReader(reader1, offset1, num2)
	buf1 := make([]byte, 20)
	for i := 0; i < 5; i++ {
		n, err := reader2.Read(buf1)
		executeIfNoErr(err, func() {
			fmt.Printf("Read(%d): %q\n", n, buf1[:n])
		})
	}
	fmt.Println()
}
func example5() {
	reader01 := strings.NewReader("MultiReader returns a Reader that's the logical concatenation of " +
		"the provided input readers.")
	reader02 := strings.NewReader("They're read sequentially.")
	reader03 := strings.NewReader("Once all inputs have returned EOF, " +
		"Read will return EOF.")
	reader04 := strings.NewReader("If any of the readers return a non-nil, " +
		"non-EOF error, Read will return that error.")
	fmt.Println("创建一个multi-reader, 带有4个reader")
	reader1 := io.MultiReader(reader01, reader02, reader03, reader04)
	buf2 := make([]byte, 50)
	for i := 0; i < 8; i++ {
		n, err := reader1.Read(buf2)
		executeIfNoErr(err, func() {
			fmt.Printf("Read(%d): %q\n", n, buf2[:n])
		})
	}
	fmt.Println()
}
func example6() {
	fmt.Println("创建一个新的内存同步管道....")
	pipeReader, pipWriter := io.Pipe()
	_ = interface{}(pipeReader).(io.ReadCloser)
	_ = interface{}(pipWriter).(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 := pipWriter.Write(d)
			if err != nil {
				fmt.Printf("read error : %v\n", err)
				break
			}
			fmt.Printf("Writen(%d): %q\n", n, d)
		}
		pipWriter.Close()
	}()
	go func() {
		defer wg.Done()
		wBuf := make([]byte, 55)
		for {
			n, err := pipeReader.Read(wBuf)
			if err != nil {
				fmt.Printf("read error: %v\n", err)
				break
			}
			fmt.Printf("Read(%d): %q\n", n, wBuf[:n])
		}
	}()
	wg.Wait()
}
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."
	// 示例1:: Seek
	example1(comment)
	// 示例2: LimitReader
	example2(comment)
	// 示例3: TeeReader
	example3(comment)
	// 示例4: NewSectionReader
	example4(comment)
	// 示例5: MultiReader
	example5()
	// 示例6
	example6()
}

三、io包的接口以及它们之间的关系

没有嵌入其它接口并且只定义了一个方法的接口,总共有11个。其中有3个接口有着众多的扩展接口和实现类型,它们是:io.Readerio.Writerio.Closer

可以把这些接口分为四类:读取、写入、关闭、读写位置设定。前三个操作属于基本的I/O操作。

3.1 读操作接口

上面已经讨论,核心接口io.Reader有5个扩展接口,6个实现类型。更多的读操作接口还有:

io.ByteReaderio.RuneReader。它们分别定义了一个读取方法:ReadByteReadRune。用于读取下一个单一的字节和Unicode字符。

	var b *bytes.Buffer
	b = bytes.NewBufferString("ab")
	_ = interface{}(b).(io.ByteReader)
	_ = interface{}(b).(io.RuneReader)
	_ = interface{}(b).(io.ByteScanner)
	_ = interface{}(b).(io.RuneScanner)
	// io.ByteReader
	var reader01 *strings.Reader
	reader01 = strings.NewReader("aa")
	_ = interface{}(reader01).(io.ByteReader)
	_ = interface{}(reader01).(io.RuneReader)
	_ = interface{}(reader01).(io.ByteScanner)
	_ = interface{}(reader01).(io.RuneScanner)

strings.Readerbytes.Buffer都是io.ByteReaderio.RuneReader的实现类型。同时,这两个接口,还都实现了io.ByteScannerio.RuneScanner

type ByteScanner interface {
	ByteReader
	UnreadByte() error
}

io.ByteScanner接口内嵌了简单接口io.ByteReader、并额外定义了UnreadByte方法,这样,它就抽象出一个能够读取和读回退单字节的功能集。

type RuneScanner interface {
	RuneReader
	UnreadRune() error
}

io.RuneScanner接口内嵌了简单接口io.RunneReader,并额外定义了UnreadRune方法。这样,它就抽象出一个能够读取和读回退单个Unicode字符的功能集。

io.ReaderAt接口只定义了一个方法ReadAt。ReadAt是一个纯粹的只读方法。

它只读其所属值中包含的字节,而不对这个值进行真正的修改。比如,它绝对不能修改已读计数的值。

io.WriterTo接口,定义了一个名为WriteTo的方法。它只会接受一个io.Writer类型的参数值,并从该参数值中读出数据,并写入其所属值中。

与之对应的接口是io.ReaderFrom

io.CopyN函数,在复制数据的时候,会检查其参数src,是否实现了io.WriterTo接口。如果是,那么它就直接利用该值的WriteTo方法,把其中的数据拷贝给参数dst参数的值。

类似地,这个函数还会检查dst的值是否实现了io.ReaderFrom接口。如果是,那么它就会利用这个值的ReadFrom方法,直接从src那里把数据拷贝到该值。

io.Copyio.CopyBuffer,和io.CopyN一样。因为它们内部复制到时候,使用同一套代码。

3.2 写操作接口

io.ReaderFrom接口,它定义了一个名叫ReadFrom的写入方法。该方法接受一个io.Reader类型的参数值。并会从该参数值中读取数据,并写入到所属值中。

基于io.Writer 扩展的接口

io.ReadWriter

*io.pipe就是io.ReadWriter 接口的实现类型。

io.ReadWriteClose

io.ReadWriteSeeker

io.WriteCloser

io.WriteSeeker

io.ByteWriter

io.WriterAt

*io.File不但是io.WriterAt的实现类型,同时还实现了io.ReadWriterCloserio.ReadWriteSeeker接口。

3.3 读写位置设定接口

io.Seeker接口作为一个读写位置设定相关的接口,仅定义了一个方法,叫Seek

基于io.Seeker扩展的接口:

io.ReadSeeker

io.ReadWriteSeeker

io.WriteSeeker

io.WriteSeeker是基于io.Writerio.Seeker的扩展接口

*strings.Reader*io.SectionReader都实现了io.Seeker接口,这两个类型也都是io.ReaderAt接口的实现类型。

	var reader02 *strings.Reader
	reader02 = strings.NewReader("aa")
	_ = interface{}(reader02).(io.Seeker)
	_ = interface{}(reader02).(io.ReaderAt)
	var sectionReader01 *io.SectionReader
	sectionReader01 = io.NewSectionReader(reader02, 0, 1)
	_ = interface{}(sectionReader01).(io.Seeker)
	_ = interface{}(sectionReader01).(io.ReaderAt)

3.4 关闭操作

io.Closer

它的实现类型,在io包里只有io.PipeReaderio.PipeWriter

四、总结11个简单接口和9个扩展接口

4.1 读取操作接口有5个

io.Reader

io.ByteReader

io.RuneReader

io.ReaderAt

io.WriterTo

4.2 写入操作接口有4个

io.Writer

io.ByteWriter

io.WriterAt

io.ReaderFrom

4.3 关闭操作接口有1个

io.Closer

4.4 读写位置设定的接口有1个

io.Seeker

4.5 基于11简单接口的扩展接口有9个

io.ReadWriter

io.ReadCloser

io.ReadSeeker

io.ByteScanner

io.RuneScanner

io.ReadWriteCloser

io.ReadWriteSeeker

io.WriteCloser

io.WriteSeeker

到此这篇关于golang IO接口与工具使用方法讲解的文章就介绍到这了,更多相关GO IO接口与工具内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

您可能感兴趣的文档:

--结束END--

本文标题: GOLang IO接口与工具使用方法讲解

本文链接: https://www.lsjlt.com/news/200290.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • GOLang IO接口与工具使用方法讲解
    目录一、io包中接口的好处和优势1.1拷贝数据的函数二、在io包中io.Reader的扩展接口和实现类型2.1 io.Reader的扩展接口2.2 io.Reader接口的实现类型2...
    99+
    2023-03-19
    GO IO接口 GO工具
  • GOLang IO接口与工具如何使用
    这篇文章主要介绍“GOLang IO接口与工具如何使用”,在日常操作中,相信很多人在GOLang IO接口与工具如何使用问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”GOLang ...
    99+
    2023-07-05
  • java接口使用默认方法的讲解
    1、接口中默认方法的格式: public default返回值类型方法名(参数列表) { } 2、接口中默认方法的注意事项: 默认的方法不是抽象的方法,所以不重写。但是可以重写...
    99+
    2022-11-12
  • Java BeanUtils工具类常用方法讲解
    谨慎使用这个copyproperties这个功能,相同的属性都会被替换,不管是否有值  BeanUtils 是 Apache commons组件的成员之一,主要用于简化J...
    99+
    2022-11-12
  • Golang开发之接口的具体使用详解
    目录Golang的接口是什么什么情况下要用接口实战案例多态的例子定义通用方法的例子松耦合的例子实现插件化架构的例子Golang的接口是什么 在 Golang 中,接口是一种类型,它是...
    99+
    2023-05-14
    Golang接口使用 Golang接口 Go 接口
  • Java超详细讲解接口的实现与用法
    目录1.接口的定义2.接口的实现3.接口的引用4.接口的继承5.利用接口实现多重继承1.接口的定义 接口是一种特殊的抽象类,是Java提供的一个重要的功能,与抽象类不同的是: 接口的...
    99+
    2022-11-13
  • Javaweb使用Maven工具与Tomcat的方法详解
    目录一、Maven工具1,关于maven2、安装maven3,使用maven4,认识pom.xml5,目录文件完善6,导入数据库的依赖二、Tomcat1,Tomcat 是什么2,下载...
    99+
    2022-11-13
  • JavaFeign微服务接口调用方法详细讲解
    目录Feign说明引入依赖启动类开启客户端Feign接口开发编写容错类在业务层调用Feign客户端接口Feign的常用属性如下Feign说明 Feign是一种声明式、模板化的HTTP...
    99+
    2023-01-29
    Java Feign微服务接口调用 Java Feign微服务调用
  • 实例讲解golang中regex库的使用方法
    随着大数据时代的到来,对数据处理能力的要求越来越高。因此,对于程序开发者来说,灵活、高效的数据处理能力显得尤为重要。在这方面,golang的regex库能够满足程序开发者的需求。golang的regex库提供了一些用于匹配和替换模式的函数,...
    99+
    2023-05-14
  • Java超详细讲解抽象类与接口的使用
    目录一、抽象类1、抽象类的语法2、抽象类的特性3、抽象类的作用二、接口1、接口的概念2、接口使用3、接口特性4、实现多个接口5、接口间的继承6、常用的接口(1)Comparable接...
    99+
    2022-11-13
  • golang接口断言的使用方法是什么
    在Go中,接口断言是一种将接口类型的值转换为其他具体类型的方法。接口断言可以使用类型断言表达式来进行,其语法为: value, ok...
    99+
    2023-10-23
    golang
  • redux工作原理讲解及使用方法
    目录1. redux 是什么?2.redux的原理3. 如何使用 redux?(1).安装redux,创建redux文件夹,建立store.js(2).建立reducers.js(3...
    99+
    2022-11-12
  • AndroidSurfaceView与TextureView使用方法详细讲解
    目录SurfaceSurfaceViewTextureViewSurfaceTextureSurfaceView和TextureView的区别Surface 官方对Surface的解...
    99+
    2022-11-13
    Android SurfaceView与TextureView Android TextureView Android SurfaceView
  • SpringBoot项目使用hutool工具进行http接口调用的处理方法
    目录写作目的hutool简单介绍实践引用依赖postget 请求end写作目的 在实际的开发过程中一个互联网的项目来说 ,有可能会涉及到调用外部接口的实际业务场景,原生的比如使用ht...
    99+
    2022-11-13
  • Linux下端口映射工具rinetd的使用方法
    Linux下端口映射工具rinetd的使用方法,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。Linux下简单好用的工具rinetd,实现端口映射/转发/重定向软...
    99+
    2023-06-05
  • Java List接口与Iterator接口及foreach循环使用的方法
    这篇文章主要介绍“Java List接口与Iterator接口及foreach循环使用的方法”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Java List接口与Iterator...
    99+
    2023-06-30
  • Javaweb如何使用Maven工具与Tomcat的方法
    小编给大家分享一下Javaweb如何使用Maven工具与Tomcat的方法,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!一、Maven工具1,关于mavenMav...
    99+
    2023-06-29
  • C++stack与queue使用方法详细讲解
    目录Stack的介绍和使用stack的默认定义的模板stack的使用queue的介绍和使用queue的默认定义的模板queue的使用Stack的介绍和使用 stack的文档介绍 st...
    99+
    2023-01-04
    C++ stack与queue C++ stack使用方法 C++ queue使用方法
  • win10安装工具下载使用方法详解
    对于电脑小白而言,重装系统并不是件容易的事情。如果一个网友想要安装Win10系统却不知道如何操作,应该怎么办呢?。我们可以可以借助win10安装工具轻松实现安装系统的目的,下面小编就教下大家win10安装工具下载使用方法。我们可以借助魔法猪...
    99+
    2023-07-14
  • 微信域名检测api接口分享与使用方法详解
    微信域名检测可以让我们很方便的了解所有推广域名在微信中的状态,实时检测出在微信中有问题的域名,减少域名无法打开而带来的损失。那么微信域名检测api接口如何使用呢?今天给大家分享一个微信域名检测api接口,以及详解使用方法。微信域名检测api...
    99+
    2023-06-04
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作