zoukankan      html  css  js  c++  java
  • Go IO && bufio

    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))
    
  • 相关阅读:
    LeetCode#1047-Remove All Adjacent Duplicates In String-删除字符串中的所有相邻重复项
    LeetCode#345-Reverse Vowels of a String-反转字符串中的元音字母
    LeetCode#344-Reverse String-反转字符串
    LeetCode#232-Implement Queue using Stacks-用栈实现队列
    LeetCode#225-Implement Stack using Queues-用队列实现栈
    LeetCode#20-Valid Parentheses-有效的括号
    树的遍历
    [leetcode] 树(Ⅰ)
    二叉树图形化显示
    你错在成长于文明的边陲
  • 原文地址:https://www.cnblogs.com/alin-qu/p/10225268.html
Copyright © 2011-2022 走看看