go---bufio 包中的数据类型

本文详细介绍了Go语言标准库中的bufio包,包括bufio.Reader和bufio.Writer的使用方法,如缓冲区的填充、不同读取方法的区别及如何实现高效的数据写入。

bufio.Reader 中的缓冲区

package main

import (
	"fmt"
	"bufio"
	"strings"
)

func main() {
	comment := "Package bufio implements buffered I/O. " +
		"It wraps an io.Reader or io.Writer object, " +
		"creating another object (Reader or Writer) that " +
		"also implements the interface but provides buffering and " +
		"some help for textual I/O."
	basicReader := strings.NewReader(comment)
	fmt.Printf("The size of basic reader: %d\n", basicReader.Size())
	fmt.Println()

	fmt.Println("New a buffered reader ...")
	// 缓冲区的默认尺寸为 4 KB
	reader1 := bufio.NewReader(basicReader)
	fmt.Printf("The default size of buffered reader: %d\n", reader1.Size())
	// 此时 reader1 的缓冲区还没有被填充
	fmt.Printf("The number of unread bytes in the buffer: %d\n", reader1.Buffered())

	// Peek 和 ReadSlice 方法都会调用 fill 方法
	// fill 方法的作用是填充内部缓冲区
	// fill 方法先检查所属值的已读计数,如果不大于 0,有两种可能
	// 1. 缓冲区中的字节全是新的
	// 2. 缓冲区刚被压缩过,那么 
	// (1) 把缓冲区中在 [已读计数, 已写计数) 内的值拷贝到缓冲区头部
	// (2) 将已写计数的新值设为原已写计数与原已读计数的差,代表压缩后第一次写入字节时的索引
	// 实际上,fill 方法只有在开始时发现所属的已读计数大于 0,就对缓冲区进行一次压缩
	bytes, err := reader1.Peek(7)
	if err != nil {
		fmt.Printf("error: %v\n", err)
	}
	fmt.Printf("Peeked contents(%d): %q\n", len(bytes), bytes)
	fmt.Printf("The number of unread bytes in the buffer: %d\n", reader1.Buffered())
	fmt.Println()

	buf1 := make([]byte, 10)
	n, err := reader1.Read(buf1)
	if err != nil {
		fmt.Printf("error: %v\n", err)
	}
	fmt.Printf("Read contents(%d): %q\n", n, buf1)
	fmt.Printf("The number of unread bytes in the buffer: %d\n", reader1.Buffered())
	fmt.Println()

	fmt.Printf("Reset the baseic reader (size: %d) ...\n", len(comment))
	basicReader.Reset(comment)
	fmt.Printf("Reset the buffered reader (size: %d) ...\n", reader1.Size())
	reader1.Reset(basicReader)
	peekNum := len(comment) + 1
	fmt.Printf("Peek %d bytes ...\n", peekNum)
	bytes, err = reader1.Peek(peekNum)
	if err != nil {
		fmt.Printf("error: %v\n", err)
	}
	fmt.Printf("The number of peeked bytes: %d\n", len(bytes))
	fmt.Println()

	fmt.Printf("Reset the basic reader (size: %d) ...\n", len(comment))
	basicReader.Reset(comment)
	size := 300
	fmt.Printf("New a buffered reader with size %d ...\n", size)
	reader2 := bufio.NewReaderSize(basicReader, size) // 指定缓冲区大小为 300 字节
	peekNum = size + 1
	fmt.Printf("Peek %d bytes ...\n", peekNum)
	bytes, err = reader2.Peek(peekNum)
	if err != nil {
		fmt.Printf("error: %v\n", err)
	}
	fmt.Printf("The number of peeked bytes: %d\n", len(bytes))
	
	fmt.Println()
}	

在这里插入图片描述

bufio.Reader 类型的读取方法

package main

import (
	"fmt"
	"bufio"
	"strings"
)

func main() {
	comment := "Package bufio implements buffered I/O. " +
		"It wraps an io.Reader or io.Writer object, " +
		"creating another object (Reader or Writer) that " +
		"also implements the interface but provides buffering and " +
		"some help for textual I/O."
	basicReader := strings.NewReader(comment)
	fmt.Printf("The size of basic reader: %d\n", basicReader.Size())

	size := 300
	fmt.Printf("New a buffered reader with size %d ...\n", size)
	reader1 := bufio.NewReaderSize(basicReader, size)
	fmt.Println()
	
	// Peek: 从已读计数代表的索引位置开始,读取并返回其缓冲区中的 n 个未读字节
	// 在缓冲区未被填满,且其中的未读字节的数量小于 n 时,调用 fill 方法填充缓冲区
	// 但如果发现上次填充缓冲区的时候有误,则不会再次填充
	// 如果 n 比缓冲区的长度大,或比缓冲区中的未读字节数量大,则返回所有未读字节序列
	// 同时将 bufio.ErrBufferFull 作为第二个结果值返回
	// 特点:不改变已读计数
	fmt.Print("[ About 'Peek' method ]\n\n")
	peekNum := 38
	fmt.Printf("Peek %d bytes ...\n", peekNum)
	bytes, err := reader1.Peek(peekNum)
	if err != nil {
		fmt.Printf("error: %v\n", err)
	}
	fmt.Printf("Peeked contents(%d): %q\n", len(bytes), bytes)
	fmt.Printf("The number of unread bytes in the buffer: %d\n", reader1.Buffered())
	fmt.Println()

	// Read: 当缓冲区中已无字节,且参数的长度大于或等于缓冲区的长度时
	// 不会向缓冲区中写入数据,而是直接从底层读取器那里读出数据
	// 如果缓冲区中已无字节,但其长度比参数大,则先把已读计数和已写计数重置为 0
	// 然后尝试从底层读取器获取数据,对缓冲区进行一次从头到尾的填充
	// 这种尝试只进行一次,不管成功与否,然后更新已写计数
	fmt.Print("[ About 'Read' method ]\n\n")
	readNum := 38
	buf1 := make([]byte, readNum)
	fmt.Printf("Read %d bytes ...\n", readNum)
	n, err := reader1.Read(buf1)
	if err != nil {
		fmt.Printf("error: %v\n", err)
	}
	fmt.Printf("Read contents(%d): %q\n", n, buf1)
	fmt.Printf("The number of unread bytes in the buffer: %d\n", reader1.Buffered())
	fmt.Println()

	// ReadSlice: 在缓冲区的未读部分寻找给定的分隔符,并在必要时对缓冲区进行填充
	// 如果填满缓冲区后仍未找到分隔符,则把整个缓冲区作为第一个结果值返回
	// 将缓冲区已满的错误作为第二个结果值返回
	fmt.Print("[ About 'ReadSlice' method ]\n\n")
	fmt.Println("Reset the basic reader ...")
	basicReader.Reset(comment)
	fmt.Println("Reset the buffered reader ...")
	reader1.Reset(basicReader)
	fmt.Println()

	delimiter := byte('(')
	fmt.Printf("Read slice with delimiter %q...\n", delimiter)
	line, err := reader1.ReadSlice(delimiter)
	if err != nil {
		fmt.Printf("error: %v\n", err)
	}
	fmt.Printf("Read contents(%d): %q\n", len(line), line)
	fmt.Printf("The number of unread bytes in the buffer: %d\n", reader1.Buffered())
	fmt.Println()

	// ReadBytes: 会调用 ReadSlice 方法,一次又一次地填充缓冲区,并在其中寻找分隔符
	// 除非发生了未预料到的错误或者找到分隔符,或者一直进行下去
	fmt.Print("[ About 'ReadBytes' method ]\n\n")
	fmt.Println("Reset the basic reader ...")
	basicReader.Reset(comment)
	size = 200
	fmt.Printf("New a buffered reader with size %d ...\n", size)
	reader3 := bufio.NewReaderSize(basicReader, size)
	fmt.Println()

	delimiter = byte('[')
	fmt.Printf("Read bytes with delimiter %q...\n", delimiter)
	line, err = reader3.ReadBytes(delimiter)
	if err != nil {
		fmt.Printf("error: %v\n", err)
	}
	fmt.Printf("Read contents(%d): %q\n", len(line), line)
	fmt.Printf("The number of unread bytes in the buffer: %d\n", reader3.Buffered())
	fmt.Println()
}	

在这里插入图片描述

bufio.Writer

package main

import (
	"fmt"
	"bufio"
	"strings"
	"bytes"
)

func main() {
	comment := "Writer implements buffering for an io.Writer object. " +
		"If an error occurs writing to a Writer, " +
		"no more data will be accepted and all subsequent writes, " +
		"and Flush, will return the error. After all data has been written, " +
		"the client should call the Flush method to guarantee all data " +
		"has been forwarded to the underlying io.Writer."
	basicWriter1 := &strings.Builder{}

	size := 300
	fmt.Printf("New a buffered writer with size %d ...\n", size)
	writer1 := bufio.NewWriterSize(basicWriter1, size)
	fmt.Println()

	begin, end := 0, 53
	fmt.Printf("Write %d bytes into the writer ...\n", end - begin)
	// WriteString: 调用 Flush 方法
	writer1.WriteString(comment[begin:end])
	fmt.Printf("The number of buffered bytes: %d\n", writer1.Buffered())
	fmt.Printf("The number of unused bytes in the buffer: %d\n", writer1.Available())
	fmt.Println("Flush the buffer in the writer ...")
	// Flush: 把相应缓冲区中暂存的所有数据都写到底层写入器中
	// 数据一旦被写进底层写入器,就会被从缓冲区中逻辑删掉
	writer1.Flush()
	fmt.Printf("The number of buffered bytes: %d\n", writer1.Buffered())
	fmt.Printf("The number unused bytes in the bufffer: %d\n", writer1.Available())
	fmt.Println()

	basicWriter2 := &bytes.Buffer{}
	fmt.Printf("Reset the writer with a bytes buffer(an implementation of io.ReaderFrom) ...\n")
	writer1.Reset(basicWriter2)
	reader := strings.NewReader(comment)
	fmt.Println("Read data from the reader ...")
	// ReadFrom: 发现底层写入器实现了 io.ReaderFrom 接口后,将参数值的数据写进去
	writer1.ReadFrom(reader)
	fmt.Printf("The number of buffered bytes: %d\n", writer1.Buffered())
	fmt.Printf("The number of unused bytes in the buffer: %d\n", writer1.Available())
}	

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值