GO的IO接口和工具

news2024/12/24 20:27:10

GO的IO接口和工具

文章目录

  • GO的IO接口和工具
    • 一、io包中接口的好处和优势
      • 1.1拷贝数据的函数
    • 二、 在io包中,io.Reader 的扩展接口和实现类型都有哪些
      • 2.1 `io.Reader`的扩展接口
      • 2.2 `io.Reader`接口的实现类型
      • 2.3 示例
    • 三、io包的接口,以及它们之间的关系
      • 3.1 读操作接口
      • 3.2 写操作接口
      • 3.3 读写位置设定接口
      • 3.4 关闭操作
    • 四、总结11个简单接口和9个扩展接口
      • 4.1 读取操作接口有5个
      • 4.2 写入操作接口有4个
      • 4.3 关闭操作接口有1个
      • 4.4 读写位置设定的接口有1个
      • 4.5 基于11简单接口的扩展接口有9个

一、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的扩展接口

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

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

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

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

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

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

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

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

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

2.2 io.Reader接口的实现类型

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

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

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

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

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

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

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

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

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

  6. *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

Go的IO包11个简答接口和9个扩展接口

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/390397.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Raki的读paper小记:Forget-free Continual Learning with Winning Subnetworks

Abstract&Introduction&Related Work 研究任务 用子网络做CL已有方法和相关工作 彩票假说&#xff08;LTH&#xff09;证明了稀疏子网络&#xff08;称为中奖彩票&#xff09;的存在&#xff0c;这些子网络保持了密集网络的性能&#xff0c;然而使用迭代修剪方法在持续…

Splunk 的一个Bug (Events from tracker.log have not been seen)

1:背景:Splunk version: 8.2.4 splunk 的一个alert: Events from tracker.log have not been seen for the last 47 seconds, which is more than the yellow threshold (45 seconds). This typically occurs when indexing or forwarding are falling behind or are blocked…

【15】linux命令每日分享——head命令查看文件

大家好&#xff0c;这里是sdust-vrlab&#xff0c;Linux是一种免费使用和自由传播的类UNIX操作系统&#xff0c;Linux的基本思想有两点&#xff1a;一切都是文件&#xff1b;每个文件都有确定的用途&#xff1b;linux涉及到IT行业的方方面面&#xff0c;在我们日常的学习中&…

德鲁特金属导电理论(Drude)

德鲁特模型的重要等式 首先我们建立德鲁特模型的重要等式 我们把原子对于电子的阻碍作用&#xff0c;用一个冲量近似表示出来 在式子 首先定义一个等效加速度 由于 我们可以得到电导率的微观表达式 在交流电环境中 电场的表达式 借鉴上一问的公式 我们可以列出这样的表达式…

1.5 全概率公式和贝叶斯公式

1.5.1 全概率公式在处理复杂事件的概率时&#xff0c;我们经常将这个复杂事件分解为若千个互不相容的较简单的事件之和&#xff0c;先求这些简单事件的概率&#xff0c;再利用有限可加性得到所求事件的概率,这种方法就是全概率公式的思想方法全概率公式是概率论中的一个非常重要…

【CSS】CSS 复合选择器 ② ( 子元素选择器 | 交集选择器 )

文章目录一、子元素选择器1、语法说明2、代码分析3、代码示例二、交集选择器1、语法说明2、代码示例一、子元素选择器 1、语法说明 子元素选择器 可以选择 某个基础选择器 选择出的 元素组 的 直接子元素 ( 亲儿子元素 ) 中 使用基础选择器 选择 元素 ; 子元素选择器语法 : 父选…

【JAVA程序设计】(C00112)基于Springboot+Thymeleaf的在线购物商城——有文档

基于SpringbootThymeleaf的在线购物商城——有文档项目简介项目获取开发环境项目技术运行截图运行视频项目简介 基于Springbootthymeleaf框架的在线购物商城系统&#xff0c;本系统共分为二个角色&#xff1a;管理员和用户 管理员角色包含以下功能&#xff1a; 商品管理、商品…

DELL-Vostro-5468电脑 Hackintosh 黑苹果efi引导文件

原文来源于黑果魏叔官网&#xff0c;转载需注明出处。硬件型号驱动情况主板DELL-Vostro-5468处理器Intel Core i3-7100U 2.40 GHz, 3M Cache已驱动内存Samsung 8GB DDR4-2133MHz已驱动硬盘TOPMORE CAPRICORNUS NVMe 1TB已驱动显卡Intel HD Graphics 620已驱动声卡Realtek ALC2…

Linux指令——文件与权限

一&#xff0c;文件目录管理命令 ls 命令描述&#xff1a; ls命令用于显示指定工作目录下的内容。 命令格式&#xff1a;ls [参数] [目录名]。 参数说明&#xff1a; 参数 说明 -a 显示所有文件及目录&#xff08;包括隐藏文件&#xff09; -l 将文件的权限、拥有者、…

详解七大排序算法

对于排序算法&#xff0c;是我们在数据结构阶段&#xff0c;必须要牢牢掌握的一门知识体系&#xff0c;但是&#xff0c;对于排序算法&#xff0c;里面涉及到的思路&#xff0c;代码……各种时间复杂度等&#xff0c;都需要我们&#xff0c;记在脑袋瓜里面&#xff01;&#xf…

【LeetCode每日一题】——680.验证回文串 II

文章目录一【题目类别】二【题目难度】三【题目编号】四【题目描述】五【题目示例】六【解题思路】七【题目提示】八【时间频度】九【代码实现】十【提交结果】一【题目类别】 贪心算法 二【题目难度】 简单 三【题目编号】 680.验证回文串 II 四【题目描述】 给你一个字…

终端仿真器、协议分析器和 IO 监视器:IO Ninja 5.3.1 Crack

欢迎使用 IO Ninja 您的一站式终端仿真器、协议分析器和 IO 监视器 IO Ninja是一款专业的一体化终端仿真器、嗅探器和协议分析器。IO Ninja 是高度模块化的&#xff0c;并且具有适用于您可能跨越的大多数传输和协议的插件——网络&#xff08;、、、、、等&#xff09;、串行&…

实验3 设计模式实验2

实验内容: 1. 某Web 性能测试软件中包含一个虚拟用户生成器(Virtual User Generator)。 为了避免出现生成的虚拟用户数量不一致&#xff0c;该测试软件在工作时只允许启动唯一 一个虚拟用户生成器。采用单例模式设计该虚拟用户生成器&#xff0c;绘制类图并使用饿 汉式单例、双…

汇编语言程序设计(四)之汇编指令

系列文章 汇编语言程序设计&#xff08;一&#xff09; 汇编语言程序设计&#xff08;二&#xff09;之寄存器 汇编语言程序设计&#xff08;三&#xff09;之汇编程序 汇编指令 1. 数据传输指令 指令包括&#xff1a;MOV、XCHG、XLAT、LEA、LDS、LES、PUSH、POP、PUSHF、LA…

关闭应用程序遥测,禁止Windows收集用户信息

目录 1. 先创建还原点&#xff0c;防止意外 2. 界面设置 3. 服务 (1) GPEdit.msc - 本地计算机策略 - 计算机配置 - 管理模板 - Windows 组件 - 应用程序兼容性 - 关闭应用程序遥测 - 已启用 (2) GPEdit.msc - 本地计算机策略 - 计算机配置 - 管理模板 - Windows 组件 - 数…

aws apigateway 使用restapi集成lambda

参考资料 代理集成&#xff0c;https://docs.aws.amazon.com/zh_cn/apigateway/latest/developerguide/api-gateway-create-api-as-simple-proxy-for-lambda.html非代理集成&#xff0c;https://docs.aws.amazon.com/zh_cn/apigateway/latest/developerguide/getting-started-…

Android 面试必备:高工必问Binder机制~

面试可能会问到的问题 从IPC的方式问到Binder的优势为什么zygote跟其他服务进程的通讯不使用BinderBinder线程池和Binder机制 等等这些问题都是基于你对Binder的理解还有对其他IPC通讯的理解 IPC方式有多少种 传统的IPC方式有Socket、共享内存、管道、信号量等安卓特有的是Bi…

Spring AOP —— 详解、实现原理、简单demo

目录 一、Spring AOP 是什么&#xff1f; 二、学习AOP 有什么作用&#xff1f; 三、AOP 的组成 3.1、切面&#xff08;Aspect&#xff09; 3.2、切点&#xff08;Pointcut&#xff09; 3.3、通知&#xff08;Advice&#xff09; 3.4、连接点 四、实现 Spring AOP 一个简…

linux系统安装学习

文章目录一、系统安装二、命令格式和帮助三、文件目录操作命令创建目录四、cat查看文件内容、合并文件sudo获得root权限总结一、系统安装 二、命令格式和帮助 三、文件目录操作命令 ls查看目录文件 -a 显示隐藏的文件 -l 以列表的形式显示 -h 以人性化的方式显示文件内容大小 …

【java】Java 集合框架

文章目录集合框架体系如图所示集合接口集合实现类&#xff08;集合类&#xff09;集合算法如何使用迭代器遍历 ArrayList遍历 Map如何使用比较器总结早在 Java 2 中之前&#xff0c;Java 就提供了特设类。比如&#xff1a;Dictionary, Vector, Stack, 和 Properties 这些类用来…