首页 > 其他分享 >[转]go语言io reader_如何从io.Reader 中读数据

[转]go语言io reader_如何从io.Reader 中读数据

时间:2022-11-13 21:11:48浏览次数:71  
标签:读取 err nil fmt 读数据 io reader Println

 

原文:https://blog.csdn.net/weixin_39605905/article/details/111631303

------------------------

女主宣言

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

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

 

1

概述

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

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

}

一次最多读取len(p)长度的数据。
当读取遭遇到error或EOF, 会返回已读取的数据的字节数和error或EOF。
Read方法,不会修改len(p)的大小。
使用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等众多技术领域,通过夯实的技术积累和丰富的一线实战经验,为你带来最有料的技术分享


————————————————
版权声明:本文为CSDN博主「weixin_39605905」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_39605905/article/details/111631303

标签:读取,err,nil,fmt,读数据,io,reader,Println
From: https://www.cnblogs.com/oxspirt/p/16886970.html

相关文章

  • L10U4-4 Closing a presentation 20221113
    1ReadingEffectiveconclusionsUsingsubheadingstounderstandatextAtextusuallyhasatitle(title),butwritersoftenaddsubheadings(subheadings)too......
  • 【EF Core】常用的 DataAnnotations
    DataAnnotations验证常用的DataAnnotationsRequired:属性值必须非空或者不能只是空格,如果允许全空格可以[Required(AllowEmptyStrings=true)]DisplayName:显示名–......
  • ubuntu install jsoncpp and demos,StyledWriter,FastWriter,Reader,parse
    1.Installsudoapt-getinstalllibjsoncpp-dev2.Addusingheader.#include<jsoncpp/json/json.h>3.Use#include<algorithm>#include<chrono>#include<ct......
  • luogu P4786 [BalkanOI2018]Election
    题面传送门离谱题,结论出奇的简单。首先我们考虑\(O(nq)\)怎么做。显然所有C都要放在最终序列中,然后问题就变成往里面填T。我们考虑第一个T填在能填的最开始的位置上,因......
  • iOS 启动优化测试
    APP的启动在iOS中,讨论的APP的启动可以分为2种:冷启动(ColdLaunch):从零开始启动APP热启动(WarmLaunch):APP已经在内存中,在后台存活着,再次点击图标启动APP主要是针对冷启......
  • P1182 数列分段 Section II
    题干 记录为了练二分答案过程中发生了以下脑瘫错误1.加了两次最后一个数 2.这个是因为凑答案,还是对二分板子不熟属于是个二分答案的板子,记一下,代码如下其中有......
  • springboot09(condition-自动配置02)
    一、在前面condition-01中存在许多问题,比如配置烦琐,查找固定死板等等二、这个condition-自动配置02,直接使用springboot给我们的配置来更好的使用condition三、拿proper......
  • 【经验文档】 docker 启动失败 Failed to start Docker Application Container Engin
    问题现象修改docker的镜像源改为国内镜像源之后,重启docker失败,使用systemctlstatusdocker.service查看docker容器状态,发现报错:FailedtostartDockerApplicationC......
  • NGINX的重写功能(rewrite和location)
    一、常用的Nginx正则表达式字符涵义以及示例^匹配输入字符串的起始位置$匹配输入字符串的结束位置*匹配前面的字符零次或多次;如“ol*”能匹配“o”及“o......
  • Android Studio Dolphin 稳定版正式发布
     作者/YuriBlaise,ProductManager,Android为了帮助开发者们更轻松地打造高质量应用,AndroidStudio 团队深入调研,为大家带来了最新稳定版AndroidStudioDolphi......