io.Reader 解析

io.Reader 解析简介 io Reader 是一个 Interface 类型 功能非常强大 在任何需要读的地方我们都尽量使用它

简介

io.Reader 是一个 Interface 类型,功能非常强大,在任何需要读的地方我们都尽量使用它。先来看下它的原型:

type Reader interface { Read(p []byte) (n int, err error) } 

可见,任何实现了 Read() 函数的对象都可以作为 Reader 来使用。

Reader 类型

标准库中有许多不同的 Reader 类型,最常见的就是 bytes, strings 等几个库。我们或多或少都用过它们。下面来看几个最常见的例子:

(1) 文件操作
当我们调用 os.Open()打开一个文件,它会返回一个 os.File 对象,而这个对象其实就是一个 Reader 类型(因为它实现了 Read 函数):

var r io.Reader var err error r, err = os.Open("file.txt") 
var r io.Reader r = strings.NewReader("Read will return these bytes") 

(3)网络 net

type Conn interface { Read(b []byte) (n int, err error) Write(b []byte) (n int, err error) Close() error LocalAddr() Addr RemoteAddr() Addr SetDeadline(t time.Time) error SetReadDeadline(t time.Time) error SetWriteDeadline(t time.Time) error } 

当然,提供的一个私有类型 conn 是一个 struct,其实现了上述 interface。

type conn struct { fd *netFD } func (c *conn) Read(b []byte) (int, error) { ... } // Write implements the Conn Write method. func (c *conn) Write(b []byte) (int, error) { ... } 

使用场景:

conn, err := net.Dial("tcp", "google.com:80") tmp := make([]byte, 256) // using small tmo buffer for demonstrating for { n, err := conn.Read(tmp) if err != nil { if err != io.EOF { fmt.Println("read error:", err) } break } buf = append(buf, tmp[:n]...) } 

或者

func main() { conn, err := net.Dial("tcp", "google.com:80") if err != nil { fmt.Println("dial error:", err) return } defer conn.Close() fmt.Fprintf(conn, "GET / HTTP/1.0\r\n\r\n") var buf bytes.Buffer io.Copy(&buf, conn) fmt.Println("total size:", buf.Len()) } 

或者

func whois(domain, server string) ([]byte, error) { conn, err := net.Dial("tcp", server+":43") if err != nil { return nil, err } defer conn.Close() fmt.Fprintf(conn, "%s\r\n", domain) return ioutil.ReadAll(conn) } 

<2> http.Request 中的 body 数据就是一个 Reader

type Request struct { Method string URL *url.URL Header Header // Body is the request's body. Body io.ReadCloser Host string Form url.Values PostForm url.Values MultipartForm *multipart.Form ... } 

可以这样使用:

var r io.Reader r = request.Body 

<3> http.Post() 请求
原型:

func (c *Client) Post(url string, contentType string, body io.Reader) (resp *Response, err error) 

用法

requestBytes, _ := json.Marshal(request) requestBuf := bytes.NewBuffer(requestBytes) httpResponse, _ := c.client.Post(c.address, "text/json", requestBuf) responseBytes, _ := ioutil.ReadAll(httpResponse.Body) response := &types.RPCResponse{} err = json.Unmarshal(responseBytes, response) 

或者

resp, err := http.Post("www.example.com/accept.php", "application/x-www-form-urlencoded", strings.NewReader("name=alex")) 

(4) bytes.Buffer
是 struct 类型,但同时也是一个 Reader/Writer,因为它实现了 Read() /Writer() 等函数。

type Buffer struct { buf []byte // contents are the bytes buf[off : len(buf)] off int // read at &buf[off], write at &buf[len(buf)] bootstrap [64]byte // memory to hold first slice; helps small buffers avoid allocation. lastRead readOp // last read operation, so that Unread* can work correctly. } func (b *Buffer) Read(p []byte) (n int, err error) { b.lastRead = opInvalid if b.off >= len(b.buf) { // Buffer is empty, reset to recover space. b.Truncate(0) if len(p) == 0 { return } return 0, io.EOF } n = copy(p, b.buf[b.off:]) b.off += n if n > 0 { b.lastRead = opRead } return } 
 bs, err := json.Marshal(data) if err != nil { return err } return io.Copy(os.Stdout, bytes.NewReader(bs)) 

(5) bufio
标准库 bufio 提供了对 io.Reader 和 io.Writer 等 I/O 对象的封装,实现了缓冲的功能。
比如 :

func NewReader(rd io.Reader) *Reader func NewWriterSize(w io.Writer, size int) *Writer func NewReadWriter(r *Reader, w *Writer) *ReadWrite func NewScanner(r io.Reader) *Scanner 
reader := bufio.NewReader(os.Stdin) 

或者初始化一个 bytes.Buffer 对象,然后据此生成一个 bufio.Reader 对象

readbuffer := bytes.NewBuffer([]byte("input string to be read into new buffer")) reader := bufio.NewReader(readbuffer) 

由于 net.Conn 也是一个 Reader,因此还可以为它来创建一个 bufio.Reader,如下:

listener, err:= net.Listen("tcp", ":8888") for { conn, _ := listener.Accept() ... } reader := bufio.NewReader(conn) 

(6) 编解码 Decoder

func receive(conn net.Conn) { dec := json.NewDecoder(conn) msg := new(Message) err := dec.Decode(msg) } 

原型

func NewDecoder(r io.Reader) *Decoder { return &Decoder{r: r} } 

注: 由于 conn 是一个 interface,声明了 Read() , Write() 等方法, 因此这里很方便的就可以作为 Reader 使用了。

除此之外,GO 语言标准库中还有很多 Reader 类型,我们应该在一切能使用它们的场景下都尽量使用它们。

使用 Reader

上面我们看了一些不同的 Reader 类型,现在我们看一下如何使用它们

(1)直接调用该 Reader 对象的 Read() 函数来读取数据

p := make([]byte, 256) n, err := r.Read(p) 

(2)使用 ioutil.ReadAll 从一个 Reader 中读取数据,返回 raw []byte

b, err := ioutil.ReadAll(r) 

(3)使用 io.Copy() 从一个 Reader 中读取数据,并写入一个 Writer

n, err := io.Copy(w, r) 

(4)使用 JSON Decoder 从一个 Reader 中直接 decode 数据

err := json.NewDecoder(r).Decode(v) 

(5)从一个已经 gzipped 了的 []byte 数据的 Reader 中创建一个 gzip.Reader

r = gzip.NewReader(r) 

这样的话,从这个新创建的 reader 中读取数据的话就是已经自动 unzipped 的数据了。

设计 Reader 接口

func Reverse(s string) (string, error) 

可以变成

func Reverse(r io.Reader) io.Reader 

这样改变之后,如果别人想要传入一个 string,那么它可以这样:

r = Reverse(strings.NewReader("Make me backwards")) 

如果别人想要传入一个文件对象,可以这样:

f, err := os.Open("file.txt") if err != nil { log.Fatalln(err) } r = Reverse(f) 

或者,还可以传入一个 http.Request.Body

func handle(w http.ResponseWriter, r *http.Request) { rev := Reverse(r.Body) // etc... } 

 

今天的文章 io.Reader 解析分享到此就结束了,感谢您的阅读。
编程小号
上一篇 2025-01-03 14:40
下一篇 2025-01-03 14:33

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/bian-cheng-ji-chu/100544.html