Go
原生的pkg
中有一些核心的interface
,其中io.Reader/Writer
是比较经常使用的接口。不少原生的结构都围绕这个系列的接口展开,在实际的开发过程当中,你会发现经过这个接口能够在多种不一样的io类型之间进行过渡和转化。本文结合实际场景来总结一番。网络
围绕io.Reader/Writer
,有几个经常使用的实现:ui
[]byte
抽象成Reader[]byte
抽象成Reader和Writer这些实现对于初学者来讲其实比较难去记忆,在遇到实际问题的时候更是一脸蒙圈,不知如何是好。下面用实际的场景来举例编码
encoding/base64
包中:spa
func NewEncoder(enc *Encoding, w io.Writer) io.WriteCloser
这个用来作base64
编码,可是仔细观察发现,它须要一个io.Writer做为输出目标,并用返回的WriteCloser
的Write方法将结果写入目标,下面是Go官方文档的例子code
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())
这种场景常常用在基于字节的协议上,好比有一个具备固定长度的结构:开发
type Protocol struct { Version uint8 BodyLen uint16 Reserved [2]byte Unit uint8 Value uint32 }
经过一个[]byte
来反序列化获得这个Protocol
,一种思路是遍历这个[]byte
,而后逐一赋值。其实在encoding/binary
包中有个方便的方法:rem
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()
好比对于常见的基于文本行的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')) //... }
a := "Hello, playground" fmt.Println([]byte(a))
等价于
a := "Hello, playground" buf := new(bytes.Buffer) buf.ReadFrom(strings.NewReader(a)) fmt.Println(buf.Bytes())