女主宣言

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)

return 0, ErrShortBuffer

}

for n

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等众多技术领域,通过夯实的技术积累和丰富的一线实战经验,为你带来最有料的技术分享

go语言io reader_如何从io.Reader 中读数据相关推荐

  1. 如何从io.Reader 中读数据

    女主宣言 Go语言以其本身具有的高并发特性,在云计算开发中,得到了广泛的应用,也深受广大开发者的欢迎.但是大家对go语言真的理解了么?本文作者经过对go语言的多年实践应用,现对go语言中如何从io.R ...

  2. Flink系列之:基于scala语言实现flink实时消费Kafka Topic中的数据

    Flink系列之:基于scala语言实现flink实时消费Kafka Topic中的数据 一.引入flink相关依赖 二.properties保存连接kafka的配置 三.构建flink实时消费环境 ...

  3. C语言 | 建立链表,输出各结点中的数据

    例42:C语言实现一个简单链表,它由3个学生数据的结点组成,要求输出各结点中的数据. 解题思路:读者在学习这道例题的时候,应该首先分析三个问题. 各个结点是怎么样构成链表的? 没有头指针head行不行 ...

  4. c语言读取网页文本内容,从文本文件中读取数据

    请问如何用c语言从txt文件中读取数据? 请问如何用c语言从txt文件中读取数据? 就是用空格分开的数据,例如:12//其中的in.txt就是你要读取数据的文件,当然把它和程序放在同一目录 - #in ...

  5. 中数据逆序输出_C语言 | 建立链表,输出各结点中的数据

    例42:C语言实现一个简单链表,它由3个学生数据的结点组成,要求输出各结点中的数据. 解题思路:读者在学习这道例题的时候,应该首先分析三个问题. 各个结点是怎么样构成链表的? 没有头指针head行不行 ...

  6. C语言函数sscanf:从一个字符串中读进与指定格式相符的数据

    转载自:http://www.aiseminar.cn/html/07/t-407.html C的split string函数--sscanf sscanf 名称: sscanf() - 从一个字符串 ...

  7. C语言:使用冒泡算法将数组中的数据从大到小进行排序

    /*使用冒泡算法将数组中的数据从大到小进行排序*/ #include<stdio.h> #define N 5 int main() {int a[N];int i,j,t;printf( ...

  8. 【多线程】0.理解一下5种IO模型、阻塞IO和非阻塞IO、同步IO和异步IO

    5种IO模型.阻塞IO和非阻塞IO.同步IO和异步IO 看了一些文章,发现有很多不同的理解,可能是因为大家入切的角度.环境不一样.所以,我们先说明基本的IO操作及环境. 本文是在<UNIX网络编 ...

  9. 详解磁盘IO、网络IO、零拷贝IO、BIO、NIO、AIO、IO多路复用(select、poll、epoll)

    文章很长,但是很用心! 文章目录 1. 什么是I/O 2. 磁盘IO 3. 网络IO 4. IO中断与DMA 5. 零拷贝IO 6. BIO 7. NIO 8. IO多路复用 8.1 select 8 ...

  10. 5种IO模型、阻塞IO和非阻塞IO、同步IO和异步IO

    5种IO模型.阻塞IO和非阻塞IO.同步IO和异步IO 看了一些文章,发现有很多不同的理解,可能是因为大家入切的角度.环境不一样.所以,我们先说明基本的IO操作及环境.本文是在<UNIX网络编程 ...

最新文章

  1. 2021春季学期-创新设计与实践-Lesson5
  2. win7+centos7.2双系统安装
  3. 作为网站管理,你的性能监测工作如何开展?
  4. Linux上通过SUU更新Dell服务器固件
  5. HDU1848 Fibonacci again and again【SG函数】
  6. ref 和out的区别
  7. php点击按钮变文字,点击按钮文字变成input框,点击保存变成文字的实现代码
  8. ndows外壳公用dll,Windows外壳公用DLL已停止工作
  9. Atitit Cookie安全法 目录 1. cookie分为 会话cookie 和 持久cookie , 1 1.1. 安全措施 1 1.2. 3. cookie的同源策略 2 1.3. 安全类库
  10. 清华姚班和100个张小龙
  11. 【VFB】复制VB代码(VB与FB的差异)(VFB教程3-6)
  12. [转]KSN报告:2014 - 2016年的PC勒索软件
  13. 谢逸计算机网络,第一届中国计算机实践教育学术会议在南京成功举办
  14. 一行 Python 代码能实现什么丧心病狂的功能?
  15. 服务器安全狗Windows V5.0正式版
  16. 【FFmpeg】avg_frame_rate 计算 及在TS 中使用
  17. VS2015 C++ 海鼎MPOS更新程序
  18. 超快速结构感知深度巷道检测(Ultra Fast Structure-aware Deep Lane Detection )
  19. python微信图片dat转码
  20. 关于计算机的一些常识

热门文章

  1. 规定计算机系统实现安全等级保护,计算机信息系统安全等级保护标准体系包括:信息系统安全保.DOC...
  2. SortedList 用法
  3. pkcs1与pkcs8格式RSA私钥互相转换
  4. 关于期权的若干硬知识,知道这些就不那么担心了
  5. javascript DOM操作
  6. Spanning-Tree Portfast
  7. 关于Google Instant 你必须知道的6件事情,互联网营销
  8. java伪代码 读后感
  9. 远在美国的凤姐为何选择回国理財?
  10. 找回WordPress登录密码的方法