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. Python中的print()语句

    Python中print()语句的相关使用 介绍 print()函数可以将输出的信息打印出来,即发送给标准输出流.Python中可以直接使用print()函数,将信息展示在控制台 基本使用方法 输出数 ...

  2. Kubernetes入门实践(Pods)

    为了解决多应用联合运行的问题,同时还要不破坏容器的隔离,就要再对多个容器进行打包.Pod就是对容器的打包,里面的容器可以看成是一个整体,总是能一起调度.一起运行,绝不会出现分离的情况,而Pod属于Ku ...

  3. 一文教你如何使用Node进程管理工具-pm2

    pm2 是什么 pm2 是一个守护进程管理工具,它能帮你守护和管理你的应用程序.通常一般会在服务上线的时候使用 pm2 进行管理.pm2 能做的其实有很多,比如监听文件改动自动重启,统一管理多个进程, ...

  4. Tomacat乱码和报错UTF-8 序列的字节 2 无效和‘application/json;charset=UTF-8‘ not supported的处理

    文章目录 前言 1. tomcat乱码的处理方法 2. applicationContext.xml报错2 字节的 UTF-8 序列的字节 2 无效 3. 报错'application/json;ch ...

  5. Docker compose单机编排工具

    Docker compose单机编排工具 目录 Docker compose单机编排工具 docker-compose介绍 Docker Compose使用的三步: docker-compose安装部 ...

  6. 2021-12-23:每日温度。 请根据每日 气温 列表 temperatures ,请计算在每一天需要等几天才会有更高的温度。如果气温在这之后都不会升高,请在该位置用 0 来代替。 示例 1: 输

    2021-12-23:每日温度. 请根据每日 气温 列表 temperatures ,请计算在每一天需要等几天才会有更高的温度.如果气温在这之后都不会升高,请在该位置用 0 来代替. 示例 1: 输入 ...

  7. SRE方法论之拥抱风险

    一.系统不可能100%可靠 系统不可能100%可靠,人都不可能100%健康,更何况我们人类创造的系统?所以,任何软件系统都不应该一味地追求 100%可靠.事实证明,可靠性超过一定值后,再提高可靠性对于 ...

  8. react eject提示This git repository has untracked files or uncommitted changes:

    在yarn eject 但时 老是提示This git repository has untracked files or uncommitted changes: Remove untracked ...

  9. 安装vue后 vue -V查不到版本号 添加环境变量没反应

    萌新一枚,今天听老大说后续有项目要用vue,于是找教程自己先看看, 验证vue是否安装成功时,提示 'vue' 不是内部命令,也不是可运行的程序 有说把vue路径添加环境变量的,试了一下,不行(后来看 ...

  10. # 代码随想录算法训练营Day31 贪心算法| 1005.K次取反后最大化的数组和 134. 加油站 135. 分发糖果

    代码随想录算法训练营 1005.K次取反后最大化的数组和 题目链接:1005.K次取反后最大化的数组和 给定一个整数数组 A,我们只能用以下方法修改该数组:我们选择某个索引 i 并将 A[i] 替换为 ...