Go原生的pkg中有一些核心的interface,其中io.Reader/Writer是比较常用的接口。很多原生的结构都围绕这个系列的接口展开,在实际的开发过程中,你会发现通过这个接口可以在多种不同的io类型之间进行过渡和转化。本文结合实际场景来总结一番。

总览

围绕io.Reader/Writer,有几个常用的实现:

  • net.Conn, os.Stdin, os.File: 网络、标准输入输出、文件的流读取
  • strings.Reader: 把字符串抽象成Reader
  • bytes.Reader: 把[]byte抽象成Reader
  • bytes.Buffer: 把[]byte抽象成Reader和Writer
  • bufio.Reader/Writer: 抽象成带缓冲的流读取(比如按行读写)

这些实现对于初学者来说其实比较难去记忆,在遇到实际问题的时候更是一脸蒙圈,不知如何是好。下面用实际的场景来举例

场景举例

0. base64编码成字符串

encoding/base64包中:

func NewEncoder(enc *Encoding, w io.Writer) io.WriteCloser

这个用来做base64编码,但是仔细观察发现,它需要一个io.Writer作为输出目标,并用返回的WriteCloser的Write方法将结果写入目标,下面是Go官方文档的例子

input := []byte("foo\x00bar")
encoder := base64.NewEncoder(base64.StdEncoding, os.Stdout)
encoder.Write(input)

这个例子是将结果写入到Stdout,如果我们希望得到一个字符串呢?观察上面的图,不然发现可以用bytes.Buffer作为目标io.Writer

input := []byte("foo\x00bar")
buffer := new(bytes.Buffer)
encoder := base64.NewEncoder(base64.StdEncoding, buffer)
encoder.Write(input)
fmt.Println(string(buffer.Bytes())

1. []byte和struct之间正反序列化

这种场景经常用在基于字节的协议上,比如有一个具有固定长度的结构:

type Protocol struct {Version        uint8BodyLen        uint16Reserved    [2]byteUnit         uint8Value         uint32
}

通过一个[]byte来反序列化得到这个Protocol,一种思路是遍历这个[]byte,然后逐一赋值。其实在encoding/binary包中有个方便的方法:

func Read(r io.Reader, order ByteOrder, data interface{}) error

这个方法从一个io.Reader中读取字节,并已order指定的端模式,来给填充data(data需要是fixed-sized的结构或者类型)。要用到这个方法首先要有一个io.Reader,从上面的图中不难发现,我们可以这么写:

var p Protocol
var bin []byte
//...
binary.Read(bytes.NewReader(bin), binary.LittleEndian, &p)

换句话说,我们将一个[]byte转成了一个io.Reader

反过来,我们需要将Protocol序列化得到[]byte,使用encoding/binary包中有个对应的Write方法:

func Write(w io.Writer, order ByteOrder, data interface{}) error

通过将[]byte转成一个io.Writer即可:

var p Protocol
buffer := new(bytes.Buffer)
//...
binary.Writer(buffer, binary.LittleEndian, p)
bin := buffer.Bytes()

2. 从流中按行读取

比如对于常见的基于文本行的HTTP协议的读取,我们需要将一个流按照行来读取。本质上,我们需要一个基于缓冲的读写机制(读一些到缓冲,然后遍历缓冲中我们关心的字节或字符)。在Go中有一个bufio的包可以实现带缓冲的读写:

func NewReader(rd io.Reader) *Reader
func (b *Reader) ReadString(delim byte) (string, error)

这个ReadString方法从io.Reader中读取字符串,直到delim,就返回delim和之前的字符串。如果将delim设置为\n,相当于按行来读取了:

var conn net.Conn
//...
reader := NewReader(conn)
for {line, err := reader.ReadString([]byte('\n'))//...
}

花式技(zuo)巧(si)

string转[]byte

a := "Hello, playground"
fmt.Println([]byte(a))

等价于

a := "Hello, playground"
buf := new(bytes.Buffer)
buf.ReadFrom(strings.NewReader(a))
fmt.Println(buf.Bytes())

Go编程技巧--io.Reader/Writer相关推荐

  1. golang中的io.Reader/Writer

    本文整理自Go编程技巧–io.Reader/Writer Go原生的包中有一些核心的interface,其中io.Reader/Writer是比较常用的接口.很多原生的结构都围绕这个系列的接口展开,在 ...

  2. golang io.Reader和io.Writer

    文章目录 Reader和Writer bufio buffer Reader和Writer type Reader interface {Read(p []byte) (n int, err erro ...

  3. Java IO: Reader And Writer

    转载自  Java IO: Reader And Writer 译文链接 作者: Jakob Jenkov  译者: 李璟(jlee381344197@gmail.com) Java IO的Reade ...

  4. Java IO: Reader和Writer

    转载自   Java IO: Reader和Writer 作者: Jakob Jenkov 译者: 李璟(jlee381344197@gmail.com) Reader 原文链接 Reader是Jav ...

  5. go语言io reader_Go语言中的io.Reader和io.Writer以及它们的实现

    在使用Go语言的过程中,无论你是实现web应用程序,还是控制台输入输出,又或者是网络操作,不可避免的会遇到IO操作,使用到io.Reader和io.Writer接口.也也许对这两个接口和相关的一些接口 ...

  6. 正在从“vetur”获取代码操作_长时间运行 io.Reader 和 io.Writer 操作测算进度和估算剩余时间...

    每当我们在使用类似 io.Copy 和 ioutil.ReadAll 的工具时,比如我们正在从 http.Response 主体读入或者上传一个文件,我们会发现这些方法将一直堵塞,直到整个过程完成,哪 ...

  7. Go语言中的io.Reader和io.Writer以及它们的实现

    在使用Go语言的过程中,无论你是实现web应用程序,还是控制台输入输出,又或者是网络操作,不可避免的会遇到IO操作,使用到io.Reader和io.Writer接口.也也许对这两个接口和相关的一些接口 ...

  8. Go语言:字节流读写(io.Reader/io.Writer)的示例之redis读写

    读写字节流的两个基本接口定义如下: type Reader interface {Read(p []byte) (n int, err error) }type Writer interface {W ...

  9. c语言io口置1,AVR C语言编程的小技巧-IO口置位

    avr AVR C语言编程的小技巧-IO口置位 给单片机IO口置位是编程用的比较多的操作,这是我在学习C语言编程中的一点小小心得,希望大家觉得有用! AVR 单片机的IO口是标准的双向端口,首先要设置 ...

最新文章

  1. PIC在线升级源码分析
  2. 未处理的异常:进程性能计数器已禁用
  3. hdoj 1247 Hat’s Words(字典树)
  4. vscode 标准库位置_如何在VSCode中使用标准
  5. android音乐进度条设计代码,【Android】Android开发实现进度条效果,SeekBar的简单使用。音量,音乐播放进度,视频播放进度等...
  6. SAP MM模块-实施顾问岗位-面试手册-项目管理经验面试清单-英文
  7. [手把手教]discuzX2插件制作教程__最菜鸟级别的入门坎 【二】
  8. linux domino启动和停止命令,在unix平台中通过脚本来启动和停止domino和domino控制器所用的参数_lotus notes...
  9. HEVC之1 HM的使用
  10. 进位和借位问题的研究
  11. linux如何找大文件夹,Linux系统中如何查找大文件或目录文件夹的方法
  12. springboot防止表单重复提交_Spring Boot 使用 AOP 防止重复提交
  13. 通信专业顶刊_通信类权威SCI期刊(部分)
  14. 种草电商系统种草电商系统开发解决方案
  15. 用python编写倒计时_python如何倒计时
  16. 彩光价格一般是多少_复合彩光祛痘印价格多少钱?
  17. 《绝版游戏之信长之野望12—“统一日本的游戏“》
  18. linux中execvp函数,Linux shell的实现——execvp
  19. 【Web技术】1118- 图片防盗链的实现既然如此简单
  20. 苹果三代耳机_华强北airpods2 华强北三代耳机 airpodspro可调通透 主动降噪 定位改名 苹果airpodspro...

热门文章

  1. 为啥用redis解决会话呢?
  2. 使用openssl完成aes-cbc模式的数据加解密,输入和输出都是字符串的形式
  3. codeforces 1A-C语言解题报告
  4. 内存不足:杀死进程还是牺牲子进程
  5. 产品与市场,究竟哪一个重要
  6. 源码阅读 AtomicInteger
  7. 《 Spring 实战 》(第4版) 读书笔记 (未完结,更新中...)
  8. 文件系统:使用 yum 安装软件包
  9. idea 新建springboot 的 web 项目
  10. JAXB: XML绑定的Java体系结构