Golang 语言标准库 bytes 包怎么使用?

简介: Golang 语言标准库 bytes 包怎么使用?

01

介绍

Golang 语言中内置了两种字符类型,分别是 byte 的字节类类型,和 rune 的字符类类型。其中 byte 是 uint8 的别名,表示 ASCII 码的一个字符,占用 1 个字节,rune 是 int32 的别名,表示 UTF-8 字符,占用 4 个字节。

[]byte 表示字节切片,因为字符串也可以表示为字节切片,所以 bytes 包的函数和 strings 包的函数比较相似。

本文主要讲解 bytes(byte slice)包的使用方法,并不会涉及比较 string 和 []byte 相关的内容,比如二者的底层实现、区别和相互转换等。

02

函数

bytes 包提供了很多操作字节切片的函数,大致分为如下几类:

  • 比较
  • 包含
  • 索引
  • 分割
  • 转换
  • 清除

限于篇幅,我们无法将所有函数都介绍,本文我们在每个分类中挑选比较常用的函数来介绍。

比较
  • func Compare(a, b []byte) int Compare 函数用于按照字典序比较两个字节切片的大小,返回值有 3 种情况,分别是:
  • 返回 0,代表 a == b
  • 返回 -1,代表 a < b
  • 返回 +1,代表 a > b

注意:nil 作为参数,表示一个空切片。

  • func Equal(a, b []byte) bool Equal 函数用于比较两个字节切片的长度和字节是否都相等,返回值是一个 bool 类型。

注意:nil 作为函数,表示一个空切片。

包含
  • func Contains(b, subslice []byte) bool Contains 函数用于判断 subslice 子字节切片是否包含在 b 字节切片,返回值是一个 bool 类型。
  • func Count(s, sep []byte) int Count 函数用于统计 sep 字节切片在 s 字节切片中非重叠实例数。

注意:如果 sep 是一个空切片,返回值是 s 切片长度加 1。

  • func HasPrefix(s, prefix []byte) bool HasPrefix 函数用于判断字节切片 s 是否以 prefix 开头,返回值是一个 bool 类型。
  • func HasSuffix(s, suffix []byte) bool HasSuffix 函数用于判断字节切片 s 是否以 suffix 结尾,返回值是一个 bool 类型。
索引
  • func Index(s, sep []byte) int Index 函数用于查找 sep 在 s 中第一次出现的索引下标,如果没有则返回 -1。
  • func LastIndex(s, sep []byte) int LastIndex 函数用于查找 sep 在 s 中最后一次出现的索引下标,如果没有则返回 -1。
分割
  • func Split(s, sep []byte) [][]byte Split 函数用于将 sep 作为分割符,将 s 分割,返回拆分之后的字节切片。

注意:如果 sep 为空,将按照每个字节进行拆分。

  • func SplitN(s, sep []byte, n int) [][]byte SplitN 函数用于将 sep 作为分割符,将 s 分割 n 份,返回拆分之后的字节切片。
转换
  • func ToLower(s []byte) []byte ToLower 函数用于将字节切片所有字节全部转换为小写字母,返回该字节切片的一个副本。
  • func ToUpper(s []byte) []byte ToUpper 函数用于将字节切片所有字节全部转换为大小字母,返回该字节切片的一个副本。
清除
  • func Trim(s []byte, cutset string) []byte Trim 函数返回清除 s 中开头和结尾存在的 cutset 之后的一个子切片。
  • func TrimLeft(s []byte, cutset string) []byte TrimLeft 函数返回清除 s 中开头存在的 cutset 之后的一个子切片。
  • func TrimRight(s []byte, cutset string) []byte TrimRight 函数返回清除 s 中结尾存在的 cutset 之后的一个子切片。
  • func TrimSpace(s []byte) []byte TrimSpace 函数返回清除 s 中开头和结尾存在的 \t\n\r 之后的一个子切片。

03

Buffer

Buffer 定义了一个可读写和可变大小的字节缓冲区,源码如下:

type Buffer struct {
 buf      []byte // contents are the bytes buf[off : len(buf)]
 off      int    // read at &buf[off], write at &buf[len(buf)]
 lastRead readOp // last read operation, so that Unread* can work correctly.
}

阅读源码,我们发现 Buffer 结构中的字段 buf 是 []byte 类型,用于存储数据,字段 off 是 int 类型,用于记录读写位置。

创建 Buffer

创建 BUffer 有以下三种方式:

  1. var b bytes.Buffer
  2. func NewBuffer(buf []byte) *Buffer 使用 NewBuffer 函数
  3. func NewBufferString(s string) *Buffer 使用 NewBufferString 函数

注意:三种方式的区别是 2 和 3 相比 1,可以在创建 Buffer 的同时初始化数据,其中 2 和 3 的区别是创建 Buffer 时,用于初始化的数据类型不同。

Buffer 方法

Buffer 结构提供了很多方法,限于篇幅,本文也是只介绍一些比较常用的。

  • func (b *Buffer) Len() int Len 方法用于获取缓冲区未读的字节数。
  • func (b *Buffer) String() string String 方法用于将缓冲区未读数据作为字符串返回。
  • func (b *Buffer) Truncate(n int) Truncate 方法用于截断缓冲区前 n 个未读字节之后所有字节。
  • func (b *Buffer) Reset() Reset 方法用于将缓冲区置空。
  • func (b *Buffer) Grow(n int) Grow 方法用于增加 n 字节的缓冲区的容量。
  • func (b *Buffer) Read(p []byte) (n int, err error) Read 方法用于读取缓冲区 len(p) 的字节。
  • func (b *Buffer) Next(n int) []byte Next 方法用于读取缓冲区下一个 n 字节的数据。

注意:Next 方法和 Read 方法的区别是,Next 是对当前缓冲区直接进行 slice 操作并返回结果,Read 是从当前缓冲区拷贝数据到新的 slice。

  • func (b *Buffer) Write(p []byte) (n int, err error) Write 方法用于将 p 追加到当前缓冲区。
  • func (b *Buffer) WriteTo(w io.Writer) (n int64, err error) WriteTo 方法用于将缓冲区中的数据写入到一个 writer 中。

04

Reader

Reader 实现了 io.Reader, io.ReaderAt, io.WriterTo, io.Seeker, io.ByteScanner, io.RuneScanner 接口。可以读取 []byte。与 Buffer 可读写不同,Reader 是只读和支持查找。下面是 Reader 结构的源码:

type Reader struct {
 s        []byte
 i        int64 // current reading index
 prevRune int   // index of previous rune; or < 0
}

Reader 结构中的字段 s 是一个 []byte 类型,用于存储数据,字段 i 是一个 int64 类型,用于存储当前读取的索引位置。

创建 Reader
func NewReader(b []byte) *Reader

使用 NewReader 函数可以创建一个读取 b 的 Reader。

Reader 方法

Reader 也提供了很多方法,我们也将只介绍一些常用的方法。

  • func (r *Reader) Len() int Len 方法返回未读字节数。
  • func (r *Reader) Size() int64 Size 方法返回数据的总长度。
  • func (r *Reader) Reset(b []byte) Reset 方法将数据重置为 b。
  • func (r *Reader) Read(b []byte) (n int, err error) Read 方法实现了 io.Reader 接口。
  • func (r *Reader) WriteTo(w io.Writer) (n int64, err error) WriteTo 方法实现了 io.WriterTo 接口。

05

总结

本文介绍了 Golang 语言标准库的 bytes 包的函数和两个结构,Buffer 和 Reader,以及它们各自的方法。通过阅读本文,读者可以了解 bytes 包的使用方法和部分底层实现。

bytes 包提供的函数不止文中介绍的这些,感兴趣的读者,建议阅读官方文档了解文中未被提及的函数。





目录
相关文章
|
1天前
|
Go API 开发者
Golang深入浅出之-文件与目录操作:os与path/filepath包
【4月更文挑战第26天】Go语言标准库`os`和`path/filepath`提供文件读写、目录操作等功能。本文涵盖`os.Open`, `os.Create`, `os.Mkdir`, `filepath.Join`等API的使用,强调了文件关闭、路径处理、并发写入和权限问题的处理,并给出实战代码示例,帮助开发者高效、安全地操作文件与目录。注意使用`defer`关闭文件,`filepath`处理路径分隔符,以及通过同步机制解决并发写入冲突。
13 2
|
1天前
|
安全 Unix Go
Golang深入浅出之-Go语言中的时间与日期处理:time包详解
【4月更文挑战第26天】Go语言的`time`包提供处理日期和时间的功能,包括`time.Time`类型、时间戳、格式化与解析。本文讨论了核心概念、常见问题(如时区处理、格式字符串混淆、超时控制和并发安全)及解决方法。推荐使用`time.LoadLocation`管理时区,熟悉时间格式规则,用`context`精确控制超时,并注意并发安全。文中通过代码示例展示了如何获取格式化时间、计算时间差以及创建定时任务。学习和应用这些知识可提高程序的健壮性和准确性。
15 2
|
1天前
|
XML JSON Go
Golang深入浅出之-XML处理在Go语言中的实现:encoding/xml包
【4月更文挑战第26天】Go语言的`encoding/xml`库提供XML处理,包括序列化和反序列化。本文讨论了XML处理的基础,如`xml.Marshal`和`xml.Unmarshal`函数,以及常见问题和易错点,如标签命名、结构体嵌套、omitempty标签和命名空间。建议遵循标签命名规则,正确处理嵌套和属性,谨慎使用omitempty,以及理解并有效利用命名空间。文中还给出了基础示例和处理XML属性的代码示例,帮助读者掌握XML处理技巧。
11 1
Golang深入浅出之-XML处理在Go语言中的实现:encoding/xml包
|
2天前
|
JSON 编解码 Go
Golang深入浅出之-HTTP客户端编程:使用net/http包发起请求
【4月更文挑战第25天】Go语言`net/http`包提供HTTP客户端和服务器功能,简化高性能网络应用开发。本文探讨如何发起HTTP请求,常见问题及解决策略。示例展示GET和POST请求的实现。注意响应体关闭、错误处理、内容类型设置、超时管理和并发控制。最佳实践包括重用`http.Client`,使用`context.Context`,处理JSON以及记录错误日志。通过实践这些技巧,提升HTTP编程技能。
16 1
|
3天前
|
Go 开发者
Golang深入浅出之-HTTP客户端编程:使用net/http包发起请求
【4月更文挑战第24天】Go语言的`net/http`包在HTTP客户端编程中扮演重要角色,但使用时需注意几个常见问题:1) 检查HTTP状态码以确保请求成功;2) 记得关闭响应体以防止资源泄漏;3) 设置超时限制,避免长时间等待;4) 根据需求处理重定向。理解这些细节能提升HTTP客户端编程的效率和质量。
15 1
|
4天前
|
Go 开发者
Golang深入浅出之-Go语言上下文(context)包:处理取消与超时
【4月更文挑战第23天】Go语言的`context`包提供`Context`接口用于处理任务取消、超时和截止日期。通过传递`Context`对象,开发者能轻松实现复杂控制流。本文解析`context`包特性,讨论常见问题和解决方案,并给出代码示例。关键点包括:1) 确保将`Context`传递给所有相关任务;2) 根据需求选择适当的`Context`创建函数;3) 定期检查`Done()`通道以响应取消请求。正确使用`context`包能提升Go程序的控制流管理效率。
14 1
|
5天前
|
安全 Go 开发者
Golang深入浅出之-Go语言并发编程面试:Goroutine简介与创建
【4月更文挑战第22天】Go语言的Goroutine是其并发模型的核心,是一种轻量级线程,能低成本创建和销毁,支持并发和并行执行。创建Goroutine使用`go`关键字,如`go sayHello(&quot;Alice&quot;)`。常见问题包括忘记使用`go`关键字、不正确处理通道同步和关闭、以及Goroutine泄漏。解决方法包括确保使用`go`启动函数、在发送完数据后关闭通道、设置Goroutine退出条件。理解并掌握这些能帮助开发者编写高效、安全的并发程序。
14 1
|
5天前
|
SQL 关系型数据库 MySQL
Golang数据库编程详解 | 深入浅出Go语言原生数据库编程
Golang数据库编程详解 | 深入浅出Go语言原生数据库编程
|
6天前
|
Go 开发者
Golang深入浅出之-Go语言流程控制:if、switch、for循环详解
【4月更文挑战第21天】本文介绍了Go语言中的流程控制语句,包括`if`、`switch`和`for`循环。`if`语句支持简洁的语法和初始化语句,但需注意比较运算符的使用。`switch`语句提供多分支匹配,可省略`break`,同时支持不带表达式的形式。`for`循环有多种形式,如基本循环和`for-range`遍历,遍历时修改原集合可能导致未定义行为。理解并避免易错点能提高代码质量和稳定性。通过实践代码示例,可以更好地掌握Go语言的流程控制。
12 3
Golang深入浅出之-Go语言流程控制:if、switch、for循环详解
|
2月前
|
SQL 前端开发 Go
编程笔记 GOLANG基础 001 为什么要学习Go语言
编程笔记 GOLANG基础 001 为什么要学习Go语言