关于go:一文了解-ioLimitedReader类型

49次阅读

共计 3205 个字符,预计需要花费 9 分钟才能阅读完成。

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 的介绍,心愿对你有所帮忙。

正文完
 0