如何从io.Reader 中读数据

栏目: IT技术 · 发布时间: 5年前

内容简介:开发过程中,我们经常从io.Reader中读取数据。type Reader interface {

女主宣言

Go语言 以其本身具有的高并发 特性,在云计算开发中,得到了广泛的应用,也深受广大开发者的欢迎。但是大家对 go 语言真的理解了么?本文作者经过对go语言的多年实践应用,现对go语言中如何从io.Reader中读数据进行了详细介绍,相信对于go语言爱好者有很大的帮助。下来就跟随作者一起学习下吧。

PS:丰富的一线技术、多元化的表现形式,尽在“ 3 60云计算 ”,点关注哦!

如何从io.Reader 中读数据

1

概述

开发过程中,我们经常从io.Reader中读取数据。

type Reader interface {

Read(p []byte) (n int, err error)

}

  1. 一次最多读取len(p)长度的数据。

  2. 当读取遭遇到error或EOF, 会返回已读取的数据的字节数和error或EOF。

  3. Read方法,不会修改len(p)的大小。

  4. 使用io.EOF 代表结束了。

Talk is cheap. Show me the code ,下面是一个从read读取的案例:

package main

import (

"fmt"

"io"

"net"

)

func main() {

// 建立tcp连接

conn, err := net.Dial("tcp", "www.findme.wang:80")

if err != nil {

fmt.Println("dial error:", err)

return

}

defer conn.Close() // 关闭连接

// 构建http协议内容,发起http请求

httpReq := `GET / HTTP/1.0

Host: www.findme.wang

User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36

Content-Type:application/x-www-form-urlencoded

Content-Length:0

`

_, err = fmt.Fprintf(conn, httpReq)

if err != nil {

fmt.Println("http request error:", err)

return

}

// read from conn

rsData := make([]byte, 0)

for {

// 每次最多读取512 个字节

var tmp = make([]byte, 512)

n, err := conn.Read(tmp)

if n >= 0 {

rsData = append(rsData, tmp[:n]...)

}

if err == io.EOF {

fmt.Println("数据读取完毕")

break

} else if err != nil {

fmt.Println("读取数据报错:", err)

break

}

}

fmt.Println("读取的数据长度:", len(rsData))

}

在案例中,我们利用for循环反复的读,有没有简洁的方式呢?

2

利用io.copy读取

io.copy定义如下:

func Copy(dst Writer, src Reader) (written int64, err error) {

return copyBuffer(dst, src, nil)

}

将reader中内容读取到dst中的数据,读取到dst中,所以我们需要一个writer 就行,来吧,封装一个如下:

package main

import (

"fmt"

"io"

"net"

)

type MyWriter struct {

data []byte

}

func (m *MyWriter) Write(p []byte) (n int, err error) {

if m.data == nil {

m.data = make([]byte, 0)

}

if p != nil && len(p) != 0 {

m.data = append(m.data, p...)

}

return len(p), nil

}

func main() {

// 建立tcp连接

conn, err := net.Dial("tcp", "www.findme.wang:80")

if err != nil {

fmt.Println("dial error:", err)

return

}

defer conn.Close() // 关闭连接

// 构建http协议内容,发起http请求

httpReq := `GET / HTTP/1.0

Host: www.findme.wang

User- Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36

Content-Type:application/x-www-form-urlencoded

Content-Length:0

`

_, err = fmt.Fprintf(conn, httpReq)

if err != nil {

fmt.Println("http request error:", err)

return

}

w := new(MyWriter)

n, err := io.Copy(w, conn) // 将 conn中的数据读取到 writer中

if err != nil {

fmt.Println("读取err ", err)

}

//fmt.Println(string(w.data))// 打印数据

fmt.Println("读取的数据长度:", n)

}

从io读取数据虽然是简单了,但是需要封装一个writer。那么,go里面是否有类似的writer呢?能够让我们很容易获取数据的writer呢?

于是,我们找到了strings.buffer ,如下:

// A Builder is used to efficiently build a string using Write methods.

// It minimizes memory copying. The zero value is ready to use.

// Do not copy a non-zero Builder.

type Builder struct {

addr *Builder // of receiver, to detect copies by value

buf  []byte

}

有了strings.buffer,代码又可精简一波。

package main

import (

"fmt"

"io"

"net"

"strings"

)

func main() {

// 建立tcp连接

conn, err := net.Dial("tcp", "www.findme.wang:80")

if err != nil {

fmt.Println("dial error:", err)

return

}

defer conn.Close() // 关闭连接

// 构建http协议内容,发起http请求

httpReq := `GET / HTTP/1.0

Host: www.findme.wang

User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36

Content-Type:application/x-www-form-urlencoded

Content-Length:0

`

_, err = fmt.Fprintf(conn, httpReq)

if err != nil {

fmt.Println("http request error:", err)

return

}

var sb strings.Builder

n, err := io.Copy(&sb, conn) // 将 conn中的数据读取到 writer中

if err != nil {

fmt.Println("读取err ", err)

}

fmt.Println(sb.String()) // print res

fmt.Println("读取的数据长度:", n)

}

除了,使用strings.buffer,我们还可以使用bytes.Buffer。

3

使用ioutil.ReadAll

ReadAll(r io.Reader) ([]byte, error) 是一次性从输入流(reader)中读取全量数据,直到发送错误或EOF。若读取失败,返回已读数据和err;若读取成功,则返回全量数据和nil。即改方法,不会返回EOF,

案例如下:

package main

import (

"fmt"

"io/ioutil"

"net"

)

func main() {

// 建立tcp连接

conn, err := net.Dial("tcp", "www.findme.wang:80")

if err != nil {

fmt.Println("dial error:", err)

return

}

defer conn.Close() // 关闭连接

// 构建http协议内容,发起http请求

httpReq := `GET / HTTP/1.0

Host: www.findme.wang

User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36

Content-Type:application/x-www-form-urlencoded

Content-Length:0

`

_, err = fmt.Fprintf(conn, httpReq)

if err != nil {

fmt.Println("http request error:", err)

return

}

data, err := ioutil.ReadAll(conn)

if err != nil {

fmt.Println("读取err ", err)

}

fmt.Println(string(data)) // print res

fmt.Println("读取的数据长度:", len(data))

}

4

补充

此外,我们还可以使用io包提供的一些方法,比如:io.ReadAtLeast、io.ReadFull等.

1、io.ReadAtLeast

从输入流中至少min个字节,放到buf中,返回读取的字节数和err,结构如下:

func ReadAtLeast(r Reader, buf []byte, min int) (n int, err error) {

if len(buf) < min {

return 0, ErrShortBuffer

}

for n < min && err == nil {

var nn int

nn, err = r.Read(buf[n:])

n += nn

}

if n >= min { //读取字节不小于min的时候,把err 设置nil

err = nil

} else if n > 0 && err == EOF {

err = ErrUnexpectedEOF

}

return

}

  • 如果buf的长度小于 min,会触发ErrShortBuffer 。

  • 如果读取的字节数小于min,这会触发ErrUnexpectedEOF 错误。

  • 如果读取的字节数不小于min ,就算遇到了err,也会返回nil。

2、io.ReadFull 

func ReadFull(r Reader, buf []byte) (n int, err error) {

return ReadAtLeast(r, buf, len(buf))

}

io.ReadFull本质上面调用了io.ReadAtLeast,在此不再赘述。

360云计算

由360云平台团队打造的技术分享公众号,内容涉及 数据库、大数据、微服务、容器、AIOps、IoT 等众多技术领域,通过夯实的技术积累和丰富的一线实战经验,为你带来最有料的技术分享

如何从io.Reader 中读数据


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Head First jQuery

Head First jQuery

Ryan Benedetti , Ronan Cranley / O'Reilly Media / 2011-9 / USD 39.99

Want to add more interactivity and polish to your websites? Discover how jQuery can help you build complex scripting functionality in just a few lines of code. With Head First jQuery, you'll quickly g......一起来看看 《Head First jQuery》 这本书的介绍吧!

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具