IO
- IO包 是对数据流的操作。从哪里来, 怎么处理,再到哪里去。
图片来源 https://medium.com/learning-the-go-programming-language/streaming-io-in-go-d93507931185
- IO包 对数据的读写 是通过接口的形式约定的。数据的来源或者去向可能是 网络,内存,文件。
type Reader interface {
Read(p []byte) (n int, err error)
}
type Writer interface {
Write(p []byte) (n int, err error)
}
- 应用层 只需要按照接口去调用接口 不用关心底层实现细节 非常方便
package main
import (
"io"
"net/http"
"os"
"strings"
)
type R struct {
reader io.Reader
}
func NewReader(r io.Reader) *R {
return &R{
reader: r,
}
}
func (r *R) Read(p []byte) (n int, err error) {
if _, err = r.reader.Read(p); err != nil {
return
}
return len(p), nil
}
func main() {
netR, err := http.Get("https://www.bilibili.com/")
if err != nil {
panic(err)
}
defer netR.Body.Close()
fileR, err := os.Open("/tmp/data.txt")
if err != nil {
panic(err)
}
//读内存
r1 := NewReader(strings.NewReader(""))
b := make([]byte, 10*1024)
if _, err := r1.Read(b); err != nil {
panic(err)
}
//读网络
r2 := NewReader(netR.Body)
if _, err := r2.Read(b); err != nil {
panic(err)
}
//读文件
r3 := NewReader(fileR)
if _, err := r3.Read(b); err != nil {
panic(err)
}
}
bufio
- 每次对磁盘的写入或者发起网络请求 都会给系统带来压力。
将多次操作合并为一次 会减轻系统的压力 - 更优的流程是 producer --> buffer -->io.Writer
参考:https://medium.com/golangspec/introduction-to-bufio-package-in-golang-ad7d1877f762
func buffer() {
fmt.Println("IO")
w := new(W)
w.Write([]byte{'1'})
w.Write([]byte{'2'})
w.Write([]byte{'3'})
w.Write([]byte{'4'})
fmt.Println("Buffer IO")
bw := bufio.NewWriterSize(w, 3)
bw.Write([]byte{'1'})
bw.Write([]byte{'2'})
bw.Write([]byte{'3'})
bw.Write([]byte{'4'})
err := bw.Flush()
if err != nil {
panic(err)
}
}
type W struct {
}
func (*W) Write(p []byte) (n int, err error) {
fmt.Println("length is ", len(p))
fmt.Println(string(p))
return len(p), nil
}
- 普通的IO操作 会直接输出
- buffio 则会首先收集数据到缓存中 等判断buffer满了
之后才会一次性将缓存中的数据 输出。缓存中可能有多余的数据
所以需要 最后单独调用flush 函数 强制将未满的缓存 输出
ReadFrom
- 写操作之前需要 读取数据。io.ReaderFrom interface 就是
为了更加方便的 从一个reader中读取数据
type ReaderFrom interface {
ReadFrom(r Reader) (n int64, err error)
}
func ReadFrom() {
sr := strings.NewReader("read from strings reader")
w := new(W)
bw := bufio.NewWriterSize(w, 6)
if _, err := bw.ReadFrom(sr); err != nil {
panic(err)
}
if err := bw.Flush(); err != nil {
panic(err)
}
}
- bufio.Writer实现了这个接口 从reader中读取数据 io.reader -> buffer -> io.writer
ReadSlice
- 如果bufio的NewReaderSize 如果小于16个字符 会设置为默认长度16个字符
- 读取过程中 会优先判断buffer的size是否足够大 不够的话就会抛出 bufio: buffer full错误
- bufio的ReadSlice函数可以读取读取指定字符之前的字符串,如果读到字符串末尾,还没有找到指定字符串
则会返回eof
s := strings.NewReader("abc|defg
hij")
r := bufio.NewReader(s)
b, err := r.ReadSlice('|')
if err != nil {
panic(err)
}
fmt.Println(string(b))
b, err = r.ReadSlice('
')
if err != nil {
panic(err)
}
fmt.Println(string(b))