女主宣言

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

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

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 中读数据相关推荐

  1. 用python从Oracle中读数据

    将数据导入Oracle,并用python获取Oracle数据 (新手上路,不对的地方请多包涵) 背景 最近在和导师做华南地区的气象预测项目.之前获取华南各个站点的实况数据都是从别人提取出来的Excel ...

  2. 利用matlab从TXT中读数据1

    TXT是纯文本文件,常用的几种函数有load函数,importdata函数,dlmread函数,textread函数. 科学计数法如1.03乘10的8次方,可简写为"1.03e+08&quo ...

  3. go语言io reader_Go语言中异步拆分io.Reader

    在Go语言中处理任何stream数据时,我已经深陷io.Reader和io.Writer的灵活性中不能自拔.同时我在有一点上又或多或少的受了些折磨,挑战我的reader interface在你看来可能 ...

  4. golang中的io.Reader/Writer

    本文整理自Go编程技巧–io.Reader/Writer Go原生的包中有一些核心的interface,其中io.Reader/Writer是比较常用的接口.很多原生的结构都围绕这个系列的接口展开,在 ...

  5. Go编程技巧--io.Reader/Writer

    Go原生的pkg中有一些核心的interface,其中io.Reader/Writer是比较常用的接口.很多原生的结构都围绕这个系列的接口展开,在实际的开发过程中,你会发现通过这个接口可以在多种不同的 ...

  6. Spark Streaming从Kafka中获取数据,并进行实时单词统计,统计URL出现的次数

    1.创建Maven项目 创建的过程参考:http://blog.csdn.net/tototuzuoquan/article/details/74571374 2.启动Kafka A:安装kafka集 ...

  7. 存在的hive插入数据_往hive表中插入数据以及导出数据

    转载:https://blog.csdn.net/qq_26442553/article/details/80380590 转载:https://blog.csdn.net/weixin_436817 ...

  8. MATLAB将图像数据以txt文件保存以及从txt文件中读矩阵并显示图像

    网上这方面的分享挺多的,但是发现不怎么好用,下面介绍鄙人的方法 1.将一副灰度图像矩阵读入txt文件.如果你的图像是rgb的话用rgb2gray转成灰度的. 2.从txt文件中读数据到MATLAB并将 ...

  9. redis stream中pending数据的处理

    1. pending数据的产生 在消费者组模式下,当一个消息被消费者取出,为了解决组内消息读取但处理期间消费者崩溃带来的消息丢失问题,STREAM 设计了 Pending 列表,用于记录读(XREAD ...

最新文章

  1. python对数运算符号_科学网—Python中算数运算符之注意及np.logspace - 张伟的博文...
  2. 平滑迁移 Dubbo 服务的思考
  3. php写实体类,PHP实体类
  4. Python开发工程师必知十大机器学习库
  5. vaadin 10+_Vaadin 10+作为CUBA UI的未来
  6. java程会释放锁join_关于join() 是否会释放锁的一些思考
  7. 8月读书分享-《执行力是训练出来的》
  8. android中include标签使用详解
  9. 19-基础教育知识图谱赋能智慧教育
  10. Retinex图像增强算法
  11. [转载] 高校两院院士名单
  12. 企业微信登陆,操作企业微信通讯录(代码已上传github)
  13. Chrome 浏览器下载速度慢?一个开关就可解决
  14. esp8266 BH1750光照强度传感器
  15. 大疆无人机飞控软件介绍
  16. 考出PMP证书到底有没有用?
  17. SpringBoot上传大文件并支持中途取消上传
  18. 8.FastDFS分布式文件系统
  19. splice() ,split()
  20. java班组长竞聘演讲稿_班组长竞聘的演讲稿

热门文章

  1. Android处理键盘事件的小例子
  2. vue中既可以选择又可以手动输入的文本框类型_在PPT中制作一个胖乎乎的可爱圆环图...
  3. json 示例_JSON文件 数据格式及格式化转换
  4. 前端进阶之防抖与节流是什么?
  5. 怎么用class覆盖style样式
  6. 20165318 结对编程项目-四则运算 阶段总结
  7. py3下怎么用StringIO
  8. 写给90后快30岁的我们
  9. 南阳14(会场安排问题)
  10. 异常处理:你不可能总是对的 - 零基础入门学习Python032