go---bytes 包与字节串操作

strings 包主要面向的是 Unicode 字符和经过 UTF-8 编码的字符串,而 bytes 包面对的主要是字节和字节切片。

bytes.Buffer 值的长度是未读内容的长度,而不是已存内容的总长度。

strings.Reader 的 Size 方法可给出内容长度的值,用内容长度的值减去未读部分的长度,就可以方便得到已读计数。

但 bytes.Buffer 没有 Size 方法,只有 Cap 方法,而 Cap 提供的容器的容量,而不是内容的长度,所以很难估算 Bufffer 的已读计数。

package main

import (
	"bytes"
	"fmt"
)

func main() {
	var buffer1 bytes.Buffer
	contents := "Simple byte buffer for marshaling data."
	fmt.Printf("Write contents %q ...\n", contents)
	buffer1.WriteString(contents)
	fmt.Printf("The length of buffer: %d\n", buffer1.Len())
	fmt.Printf("The capacity of buffer: %d\n", buffer1.Cap())
	fmt.Println()

	p1 := make([]byte, 7)
	n, _ := buffer1.Read(p1)
	fmt.Printf("%d bytes were read. (call Read)\n", n)
	fmt.Printf("The length of buffer: %d\n", buffer1.Len())
	fmt.Printf("The capacity of buffer: %d\n", buffer1.Cap())
}	

在这里插入图片描述

bytes.Buffer 的扩容策略

package main

import (
	"bytes"
	"fmt"
)

func main() {
	var contents string
	buffer1 := bytes.NewBufferString(contents)
	fmt.Printf("The length of new buffer with contents %q: %d\n",
		contents, buffer1.Len())
	fmt.Printf("The capacity of new buffer with contents %q: %d\n",
		contents, buffer1.Cap())
	fmt.Println()

	// 容器剩余容量不够了,且容器容量 < 新长度的二倍,那么用新的容器替代原有的容器
	// 新容器的容量 = 2 * 原容器容量 + 所需字节数
	contents = "12345"
	fmt.Printf("Write contents %q ...\n", contents)
	buffer1.WriteString(contents)
	fmt.Printf("The length of buffer: %d\n", buffer1.Len())  // 0
	fmt.Printf("The capacity of buffer: %d\n", buffer1.Cap()) // 0
	fmt.Println()

	contents = "67"
	fmt.Printf("Write contents %q ...\n", contents)
	buffer1.WriteString(contents)
	fmt.Printf("The length of buffer: %d\n", buffer1.Len())
	fmt.Printf("The capacity of buffer: %d\n", buffer1.Cap())
	fmt.Println()

	// 容器容量够,在当前容器上进行长度扩充
	contents = "89"
	fmt.Printf("Write contents %q ...\n", contents)
	buffer1.WriteString(contents)
	fmt.Printf("The length of buffer: %d\n", buffer1.Len())
	fmt.Printf("The capacity of buffer: %d\n", buffer1.Cap())
	fmt.Println()

	l := make([]byte, 9)
	buffer1.Read(l)  // 读了 9 个字节
	fmt.Printf("The length of buffer: %d\n", buffer1.Len())
	fmt.Printf("The capacity of buffer: %d\n", buffer1.Cap())
	fmt.Println()

	// 容器剩余容量不够了,但如果 cap(b.buf)/2 >= len(b.buf) + need
	// 则复用现有容器,并把容器中的未读内容拷贝到头部位置,覆盖已读内容
	contents = "1011"  // 如果没有读操作的话,容器中的总字节数为 13,大于容量 12,需要扩容
	fmt.Printf("Write contents %q ...\n", contents)
	buffer1.WriteString(contents)
	fmt.Printf("The length of buffer: %d\n", buffer1.Len())
	fmt.Printf("The capacity of buffer: %d\n", buffer1.Cap())
	fmt.Print("\n\n")
}	

在这里插入图片描述

bytes.Buffer 中容易导致内容泄露的方法

内容泄露指通过某种非标准的方法得到本不该得到的内容。

Bytes 和 Next 方法可能会造成内容的泄露,因为它们都把基于内容容器的切片值直接返回给了方法的调用方。

package main

import (
	"bytes"
	"fmt"
)

func main() {
	contents := "ab"
	buffer1 := bytes.NewBufferString(contents)
	fmt.Printf("The capacity of new buffer with contents %q: %d\n",
		contents, buffer1.Cap())  // 容量为 8
	fmt.Println()

	unreadBytes := buffer1.Bytes()  // 未读内容为 [97 98]
	fmt.Printf("The unread bytes of the buffer: %v\n", unreadBytes)
	fmt.Println()

	contents = "cdefg"
	fmt.Printf("Write contents %q ...\n", contents)
	buffer1.WriteString(contents)
	fmt.Printf("The capacity of buffer: %d\n", buffer1.Cap())
	fmt.Println()

	// 内容泄露,不需要再次调用 Bytes() 就可以得到未读内容
	unreadBytes = unreadBytes[:cap(unreadBytes)]  // 基于前面的获取到的结果值
	fmt.Printf("The unread bytes of the buffer: %v\n", unreadBytes)
	fmt.Println()

	// 在外部随意操作 buffer1 的内容
	value := byte('X')
	fmt.Printf("Set a byte in the unread bytes to %v ...\n", value)
	unreadBytes[len(unreadBytes)-2] = value  
	fmt.Printf("The unread bytes of the buffer: %v\n", buffer1.Bytes())
	fmt.Println()

	// 不过,真正扩容后就无法在外部修改了,因为底层数组被重写设定了
	contents = "hijklmn"
	fmt.Printf("Write contents %q ...\n", contents)
	buffer1.WriteString(contents)
	fmt.Printf("The capacity of buffer: %d\n", buffer1.Cap())
	fmt.Println()
	
	unreadBytes = unreadBytes[:cap(unreadBytes)]
	fmt.Printf("The unread bytes of the buffer: %v\n", unreadBytes)
	fmt.Print("\n\n")
}	

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值