panic & io.reader

1. panic正常运行

package main

import (
	"fmt"
	"time"
)

func main() {
    protectRun(func(){
        fmt.Println("hello night!")
        panic("first day!")
	})
	time.Sleep(5 * time.Second)
}

func protectRun(r func()) {
     defer func(){
     	err := recover()
     	if err != nil{
     		fmt.Println(err)
		}
	 }()
     go r()
}

 

Recover 是一个Go语言的内建函数,可以让进入宕机流程中的 goroutine 恢复过来,recover 仅在延迟函数 defer 中有效,在正常的执行过程中,调用 recover 会返回 nil 并且没有其他任何效果

 

2. bufio.NewReader 及 io.reader

bufio 包实现了带缓存的 I/O 操作,它封装一个 io.Reader 或 io.Writer 对象,使其具有缓存和一些文本读写功能
 
type Reader struct {
            buf          []byte
            rd           io.Reader // reader provided by the client
            r, w         int       // buf read and write positions
            err          error
            lastByte     int
            lastRuneSize int
        }

 NewReaderSize 将 rd 封装成一个拥有 size 大小缓存的 bufio.Reader 对象,如果 rd 的基类型就是 bufio.Reader 类型,而且拥有足够的缓存,则直接将 rd 转换为基类型并返回
func NewReaderSize(rd io.Reader, size int) *Reader

NewReader 相当于 NewReaderSize(rd, 4096)
func NewReader(rd io.Reader) *Reader

----------------------------------------------------------------------------------------------------------------
io.Reader 是一个 Interface 类型,功能非常强大,在任何需要读的地方我们都尽量使用它。
先来看下它的原型:
type Reader interface {
  Read(p []byte) (n int, err error)
}
可见,任何实现了 Read() 函数的对象都可以作为 Reader 来使用。
Reader 类型
标准库中有许多不同的 Reader 类型,最常见的就是 bytes, strings 等几个库。

===========================================  以下为转载  =================================================

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     uint8
    BodyLen     uint16
    Reserved    [2]byte
    Unit        uint8
    Value       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'))
    //...
}

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())


作者:P_Chou
链接:https://www.jianshu.com/p/758c4e2b4ab8

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值