1. 引言

io.LimitedReader 提供了一个有限的读取功能,能够手动设置最多从数据源最多读取的字节数。本文我们将从 io.LimitedReader 的基本定义出发,讲述其基本使用和实现原理,其次,再简单讲述下具体的使用场景,基于此来完成对io.LimitedReader 的介绍。

2. 基本说明

2.1 基本定义

io.LimitedReader 是Go语言提供的一个Reader类型,其包装了了一个io.Reader 接口,提供了一种有限的读取功能。io.LimitedReader的基本定义如下:

type LimitedReader struct {
R Reader // underlying reader
N int64 // max bytes remaining
} func (l *LimitedReader) Read(p []byte) (n int, err error) {}

LimitedReader结构体中包含了两个字段,其中R 为底层Reader, 数据都是从Reader 当中读取的,而 N 则代表了剩余最多可以读取的字节数。同时也提供了一个Read 方法,通过该方法来实现对数据进行读取,在读取过程中 N 的值会不断减小。

通过使用io.LimitedReader, 我们可以控制从底层读取器读取的字节数,避免读取到不应该读取的数据,这个在某些场景下非常有用。

同时Go语言还提供了一个函数,能够使用该函数,创建出一个io.LimitedReader 实例,函数定义如下:

func LimitReader(r Reader, n int64) Reader { return &LimitedReader{r, n} }

我们可以通过该函数创建出一个LimitedReader 实例,也能够提升代码的可读性。

2.2 使用示例

下面我们展示如何使用io.LimitedReader 限制读取的字节数,代码示例如下:

package main

import (
"fmt"
"io"
"strings"
) func main() {
// 创建一个字符串作为底层读取器
reader := strings.NewReader("Hello, World!") // 创建一个LimitedReader,限制最多读取5个字节
limitReader := io.LimitReader(reader, 5) // 使用LimitedReader进行读取操作
buffer := make([]byte, 10)
n, err := limitReader.Read(buffer) if err != nil && err != io.EOF {
fmt.Println("读取错误:", err)
return
} fmt.Println("读取的字节数:", n)
fmt.Println("读取的内容:", string(buffer[:n]))
}

在上面示例中,我们使用字符串创建了一个底层Reader,然后基于该底层Reader创建了一个io.LimitedReader,同时限制了最多读取5个字节。然后调用 limitReaderRead 方法读取数据,此时将会读取数据放到缓冲区当中,程序将读取到的字节数和内容打印出来。函数运行结果如下:

读取的字节数: 5
读取的内容: Hello

这里读取到的字节数为5,同时也只返回了前5个字符。通过这个示例,我们展示了使用io.LimitedReader 限制从底层数据源读取数据数的方法,其实只需要使用io.LimitedReader对源Reader 进行包装,同时声明最多读取的字节数即可。

3. 实现原理

在了解了io.LimitedReader的基本定义和使用后,下面我们来对io.LimitedReader的实现原理进行基本说明,通过了解其实现原理,能够帮助我们更好得理解和使用io.LimitedReader

io.LimitedReader 的实现比较简单,我们直接看其代码的实现:

func (l *LimitedReader) Read(p []byte) (n int, err error) {
// N 代表剩余可读数据长度,如果小于等于0,此时直接返回EOF
if l.N <= 0 {
return 0, EOF
}
// 传入切片长度 大于 N, 此时通过 p = p[0:l.N] 修改切片长度,保证切片长度不大于 N
if int64(len(p)) > l.N {
p = p[0:l.N]
}
// 调用Read方法读取数据,Read方法最多读取 len(p) 字节的数据
n, err = l.R.Read(p)
// 修改 N 的值
l.N -= int64(n)
return
}

其实io.LimitedReader的实现还是比较简单的,首先,它维护了一个剩余可读字节数N,也就是LimitedReader 中的N 属性,该值最开始是由用户设置的,之后在不断读取的过程 N 不断递减,直到最后变小为0。

然后LimitedReader 中读取数据,与其他Reader 一样,需要用户传入一个字节切片参数p ,为了避免读取超过剩余可读字节数 N 的字节数,此时会比较len(p)N 的值,如果切片长度大于N,此时会使用p = p[0:l.N] 修改切片的长度,通过这种方式,保证最多只会读取到N 字节的数据。

4. 使用场景

当我们需要限制从数据源读取到的字节数时,亦或者在某些场景下,我们只需要读取数据的前几个字节或者特定长度的数据,此时使用io.LimitedReader 来实现比较简单方便。

一个经典的例子,其实是net/http 库解析HTTP请求时对io.LimitedReader的使用,通过其限制了读取的字节数。

当客户端发送HTTP请求时,可以设置头部字段 Content-Length 字段的值,通过该字段声明请求体的长度,服务端就可以根据Content-Length 头部字段的值,确定请求体的长度。服务端在读取请求体数据时,不能读取超过Content-Length 长度的数据,因为后面的数据可能是下一个请求的数据,这里通过io.LimitedReader 来确保不会读取超出Content-Length 指定长度的字节数是非常合适的,而当前net/http 库的实现也确实如此。下面是其中设置请求体的相关代码:

// 根据不同的编码类型来对 t.Body 进行设置
switch {
// 分块编码
case t.Chunked:
// 忽略
case realLength == 0:
t.Body = NoBody
// content-length 编码方式
case realLength > 0:
t.Body = &body{src: io.LimitReader(r, realLength), closing: t.Close}
default:
// realLength < 0, i.e. "Content-Length" not mentioned in header
// 忽略
}

这里realLength 便是通过Content-length 头部字段来获取的,能够取到值,此时便通过io.LimitedReader 来限制HTTP请求体数据的读取。

后续执行真正的业务流程时,此时直接调用t.BodyRead 方法读取数据即可,不需要操心读取到下一个请求体的数据,非常方便。

5. 总结

io.LimitedReader 是Go语言标准库提供的一个结构体类型,能够限制从数据源读取到的字节数。 我们先从io.LimitedReader的基本定义出发,之后通过一个简单的示例,展示如何使用io.LimitedReader 来实现读取数据数的限制。

接着我们讲述了io.LimitedReader函数的实现原理,通过对这部分内容的讲述,加深了我们对其的理解。最后我们简单讲述了io.LimitedReader 的使用场景,当我们需要限制从数据源读取到的字节数时,亦或者在某些场景下,我们只需要读取数据的前几个字节或者特定长度的数据时,使用io.LimitedReader 是非常合适的。

基于此,完成了对io.LimitedReader 的介绍,希望对你有所帮助。

一文了解 io.LimitedReader类型的更多相关文章

  1. java通过文件头来判断文件类型

    import java.io.FileInputStream; import java.io.IOException; import java.util.HashMap; import java.ut ...

  2. php 读取文件头判断文件类型的实现代码

    php代码实现读取文件头判断文件类型,支持图片.rar.exe等后缀. 例子: <?php $filename = "11.jpg"; //为图片的路径可以用d:/uploa ...

  3. php通过文件头检测文件类型通用类(zip,rar…)(转)

    在做web应用时候,通过web扩展名判断上存文件类型,这个是我们常使用的.有时候我们这样做还不完善.可能有些人上存一些文件,但是他通过修改 扩展名,让在我们的文件类型之内. 单实际访问时候又不能展示( ...

  4. MVC开发中的常见错误-07-“System.IO.DirectoryNotFoundException”类型的未经处理的异常在 mscorlib.dll 中发生

    “System.IO.DirectoryNotFoundException”类型的未经处理的异常在 mscorlib.dll 中发生 其他信息: 未能找到路径“F:\Users\home\Docume ...

  5. WPF:将Office文档、任意类型文件嵌入到EXE可执行文件中

    原文:WPF:将Office文档.任意类型文件嵌入到EXE可执行文件中 版权声明:本文为博主原创文章,未经博主允许可以随意转载 https://blog.csdn.net/songqingwei198 ...

  6. Django文档——Model字段类型(Field Types)

    大部分内容参考自http://wrongwaycn.github.io/django11/topics/db/models/index.html#topics-db-models ,内容是django ...

  7. sharepoint 2010 如何创建文档库内容类型content type

    转:http://biancheng.dnbcw.info/linux/441643.html 这次主要是记录下,如何来创建文档内容类型,例如新建文档的时候,可以选择不同模板,有word,excel文 ...

  8. 【转】python通过文件头判断文件类型

    刚刚看到一个好玩的程序,拉过来.原文地址:https://www.ttlsa.com/python/determine-file-type-by-the-file-header/ 侵权删. ===== ...

  9. FPGA之IO信号类型深入理解

    在FPGA设计开发中,很多场合会遇到同一根信号既可以是输入信号,又可以是输出信号,即IO类型(Verilog定义成inout). 对于inout型的信号,我们既可以使用FPGA原语来实现,也可以使用V ...

  10. “System.IO.FileNotFoundException”类型的未经处理的异常在 mscorlib.dll 中发生

    这个错误是我在打包的时候.发现的,由于我移动了我的project的位置(从C盘移动到了D盘),看一下出错的代码: Dim strDB As String = System.Configuration. ...

随机推荐

  1. 从零开始学Vue(二~三)—— Vue 实例 / 模板语法(插值、指令)

    概述 vue.js作为现在笔记热门的JS框架,使用比较简单易上手,也成为很多公司首选的JS框架. 但是对于初学者可能学起来有些麻烦,所以推出<从零开始学Vue>系列博客,本系列计划推出19 ...

  2. ubutn在线服务器python Package安装到离线服务器

    1.在线服务器导出requirement.txt pip freeze > requirement.txt 该文件生成完毕后,需要做些修改,去掉不需要的库,否则下载的时候会出错. 2.下载whl ...

  3. devops-5:从0开始构建一条完成的CI CD流水线

    从0开始构建一条完成的CI CD流水线 前文中已经讲述了静态.动态增加agent节点,以动态的k8s cloud为例,下面就以Maven构建Java程序为例,开始构建出一条完整的CI CD流水线. 实 ...

  4. 这是一篇记录——django-xadmin重新开发记录

    利用下面的代码把django的版本换成和xadmin2适配的版本,注意xadmin最新版本出了3.0但是就是一个纯前端的框架,和之前的版本差异较大. 因为此时距离ddl不到24小时,所以使用旧的版本. ...

  5. 【LeetCode动态规划#14】子序列系列题(最长递增子序列、最长连续递增序列、最长重复子数组、最长公共子序列)

    最长递增子序列 力扣题目链接(opens new window) 给你一个整数数组 nums ,找到其中最长严格递增子序列的长度. 子序列是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其 ...

  6. YOLO1论文中文版

    文章目录 YOLO1中文版 摘要 1. 引言 2. 统一检测 2.1 网络设计 2.2 训练 2.3 推断 2.4 YOLO的限制 3. 与其它检测系统的比较 4. 实验 4. 1 与其它实时系统的比 ...

  7. [C++提高编程] 3.1 string容器

    文章目录 3.1 string容器 3.1.1 string基本概念 3.1.2 string构造函数 3.1.3 string赋值操作 3.1.4 string字符串拼接 3.1.5 string查 ...

  8. 【性能】JDK和Jmeter的安装与配置

    一.JDK环境配置 1. 下载JDK 官网下载地址:http://www.oracle.com/technetwork/java/javase/downloads/java-archive-downl ...

  9. RocketMQ消费者是如何负载均衡的

    摘要:RocketMQ 支持两种消息模式:集群消费( Clustering )和广播消费( Broadcasting ). 本文分享自华为云社区<一文讲透RocketMQ消费者是如何负载均衡的& ...

  10. .NET Core 波场链离线签名、广播交易(发送 TRX和USDT)笔记

    Get Started NuGet You can run the following command to install the Tron.Wallet.Net in your project. ...