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())
}