go标准库之bufio模块

200 阅读4分钟

bufio

bufio 实现了有缓冲的 I/O ,它包装一个 io.Readerio.Writer 接口对象,创建另一个接口也实现了该接口,且同时还提供了缓冲和一些文本 I/O 的帮助函数对象

常量

const {
    defaultBufSize = 4096 // 默认的缓冲区大小
}

变量

var (
    ErrInvalidUnreadByte = errors.New("bufio: invalid use of UnreadByte")
    ErrInvalidUnreadRune = errors.New("bufio: invalid use of UnreadRund")
    ErrBufferFull        = errors.New("bufio: buffer full") // 缓冲区满了
    ErrNegativeCount     = errors.New("bufio: negative count") // 缓冲区的大小为负数
)
  • 错误信息
var (
    ErrTooLong         = errors.New("bufio.Scanner: token too long")
    ErrNegativeAdvance = errors.New("bufio.Scanner: SplitFunc returns negative advance count")
    ErrAdvanceTooFar   = errors.New("bufio.Scanner: SplitFunc returns negative count beyond")
)

会被 Scanner 类型返回的错误

读相关操作NewReader

NewReader

// 读取文件与strings.NewReader
func test1() {
	// r := strings.NewReader("hello world")
	f, _ := os.Open("test.txt")
	defer f.Close()

	// 也可以读取strings.NewReader中的内容
	r2 := bufio.NewReader(f)
	s, _ := r2.ReadString('\n')
	fmt.Printf("s: %v\n", s)
}

// 控制每次读取的数量
func test2() {
	s := strings.NewReader("ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890")
	br := bufio.NewReader(s)
	p := make([]byte, 10) // 每次读取10个

	for {
		n, err := br.Read(p)
		if err == io.EOF { // 读取完毕 退出
			break
		} else {
			fmt.Printf("string(p[0:n]): %v\n", string(p[0:n]))
		}
	}
}

ReadByte

// 读取与回溯
func test3() {
	s := strings.NewReader("ABCDEFG")
	br := bufio.NewReader(s)

	c, _ := br.ReadByte()    // 读取一个字节
	fmt.Printf("c: %c\n", c) // A

	c, _ = br.ReadByte()     // 读取一个
	fmt.Printf("c: %c\n", c) // B

	br.UnreadByte()          // 吐出一个
	c, _ = br.ReadByte()     // 读取一个
	fmt.Printf("c: %c\n", c) // B
}

ReadBytes

// 读取一个切片
func test6() {
	s := strings.NewReader("ABC DEF GHI JKL")
	br := bufio.NewReader(s)

	// 读取通过空格分割的切片
	w, _ := br.ReadBytes(' ')
	fmt.Printf("w: %c\n", w) // w: [A B C  ]

	w, _ = br.ReadBytes(' ')
	fmt.Printf("w: %c\n", w) // w: [D E F  ]

	w, _ = br.ReadBytes(' ') // %q 会输出为字符串
	fmt.Printf("w: %q\n", w) // w: "GHI "

	w, _ = br.ReadBytes(' ')
	fmt.Printf("w: %c\n", w) // w: [J K L]
}

ReadRune

// 读取中文、日文等
func test4() {
	s := strings.NewReader("你好,世界")
	br := bufio.NewReader(s)

	d, size, _ := br.ReadRune()
	fmt.Printf("d: %c  size: %v\n", d, size)

	d, size, _ = br.ReadRune()
	fmt.Printf("d: %c  size: %v\n", d, size)
}

ReadLine

// 读取一行
func test5() {
	s := strings.NewReader("ABC\nDEF\r\nGHI\r\nGHI")
	br := bufio.NewReader(s)

	line, isPrefix, _ := br.ReadLine()
	// 如果字符超过了4096 那么说明我们拿到的是一个前缀 isPrefix 为 true
	fmt.Printf("line: %q  isPrefix: %v\n", line, isPrefix) // line: "ABC"  isPrefix: false

	line, isPrefix, _ = br.ReadLine()
	fmt.Printf("line: %q  isPrefix: %v\n", line, isPrefix)

	line, isPrefix, _ = br.ReadLine()
	fmt.Printf("line: %q  isPrefix: %v\n", line, isPrefix)

	line, isPrefix, _ = br.ReadLine()
	fmt.Printf("line: %q  isPrefix: %v\n", line, isPrefix)
}

ReadString

// 读取字符串
func test7() {
	s := strings.NewReader("ABC DEF GHI JKL")
	br := bufio.NewReader(s)

	w, _ := br.ReadString(' ')
	fmt.Printf("w: %q\n", w) // w: "ABC "

	w, _ = br.ReadString(' ')
	fmt.Printf("w: %q\n", w) // w: "DEF "

	w, _ = br.ReadString(' ')
	fmt.Printf("w: %q\n", w) // w: "GHI "

	w, _ = br.ReadString(' ')
	fmt.Printf("w: %q\n", w) // w: "JKL"
}

WriteTo

// 写内容到缓冲区/文件中
func test8() {
	s := strings.NewReader("ABCDEFGHIJKLMN")
	br := bufio.NewReader(s)

	// 缓冲区
	// b := bytes.NewBuffer(make([]byte, 0))
	// br.WriteTo(b)
	// fmt.Printf("b: %s\n", b)

	// 也可以写到文件中 会覆盖前对应的位置 后面的不覆盖
	f, _ := os.OpenFile("test.txt", os.O_RDWR, 0777)
	br.WriteTo(f)
}

写相关操作 NewWriter

WriteString

func test9() {
	f, _ := os.OpenFile("test.txt", os.O_RDWR, 0777) // File Reader Writer
	defer f.Close()

	// 如果写入的是一个视频会更高效 因为有缓冲区的功能 会覆盖前对应的位置 后面的不覆盖
	w := bufio.NewWriter(f)
	w.WriteString("hello golang")
	w.Flush() // 刷新一下缓冲区 不然内容还在缓冲区里面 没写到文件中
}

Reset

func test10() {
	b := bytes.NewBuffer(make([]byte, 0))
	// 把b放入缓冲区
	bw := bufio.NewWriter(b)
	// 给缓冲区中写入数据
	bw.WriteString("123456789")
	c := bytes.NewBuffer(make([]byte, 0))
	// 重置缓冲区为c
	bw.Reset(c)
	bw.WriteString("abc")
	bw.Flush()     // 刷新一下缓冲区 不然内容还在缓冲区里面 没写到文件中
	fmt.Println(b) // 空 因为在重置缓冲区为c之前没有刷新 数据没写到b中
	fmt.Println(c) // abc
}

Available与Buffered

func test11() {
	b := bytes.NewBuffer(make([]byte, 0))
	bw := bufio.NewWriter(b)
	fmt.Printf("bw.Available(): %v\n", bw.Available()) // 4096默认缓冲区大小
	fmt.Printf("bw.Buffered(): %v\n", bw.Buffered())   // 0

	bw.WriteString("ABCDEFGHIJKLMN")
	fmt.Printf("bw.Available(): %v\n", bw.Available()) // 4082 缓冲区剩余大小
	fmt.Printf("bw.Buffered(): %v\n", bw.Buffered())   // 14 写入缓冲区大小
	fmt.Printf("b: %v\n", b)

	bw.Flush()
	fmt.Printf("bw.Available(): %v\n", bw.Available()) // 4096
	fmt.Printf("bw.Buffered(): %v\n", bw.Buffered())   // 0
}

WriteByte与WriteRune

func test12() {
	b := bytes.NewBuffer(make([]byte, 0))
	bw := bufio.NewWriter(b)

	// 写入缓存 一个一个写 byte等同于int8
	bw.WriteByte('H')
	bw.WriteByte('e')
	bw.WriteByte('l')
	bw.WriteByte('l')
	bw.WriteByte('o')
	bw.WriteByte(' ')
	bw.WriteRune('世')
	bw.WriteRune('界')
	bw.WriteRune('!')

	bw.Flush()
	fmt.Printf("b: %v\n", b)
}

读和写 ReadWriter

func test13() {
        // 缓冲区 用来存储 作为bw的参数
	b := bytes.NewBuffer(make([]byte, 0))
	bw := bufio.NewWriter(b)
        // 数据 用来给br读取 作为br参数
	s := strings.NewReader("123")
	br := bufio.NewReader(s)
        // br bw Reader Writer作为参数
	rw := bufio.NewReadWriter(br, bw)
        
        // 读取到br读取的内容 也就是s
	p, _ := rw.ReadString('\n')
	fmt.Printf("p: %v\n", p) // p: 123
        
        // 写入到bw的缓冲区 也就是b
	rw.WriteString("abcd")
	rw.Flush()
	fmt.Println(b) // abcd
}

Scanner

Split与ScanWords

func test14() {
	s := strings.NewReader("ABC DEF GHI JKL")
	bs := bufio.NewScanner(s)
        // 通过空格来分割
	bs.Split(bufio.ScanWords)
        
        // 每次调用 input.Scan(),即读入下一行,并移除行末的换行符;读取的内容可以调用 input.Text() 得到。Scan 函数在读到一行时返回 true,不再有输入时返回 false
	for bs.Scan() {
		fmt.Printf("bs.Text(): %v\n", bs.Text())
	}
}

/*
bs.Text(): ABC
bs.Text(): DEF
bs.Text(): GHI
bs.Text(): JKL
*/

ScanBytes与ScanRunes

func test15() {
	s := strings.NewReader("Hello 世界!")
	bs := bufio.NewScanner(s)
	// bs.Split(bufio.ScanBytes)
        // 使用ScanRunes 不然中文会乱码
	bs.Split(bufio.ScanRunes)
	for bs.Scan() {
		fmt.Printf("bs.Text(): %s\n", bs.Text())
	}
}

/*
bs.Text(): H
bs.Text(): e
bs.Text(): l
bs.Text(): l
bs.Text(): o
bs.Text():
bs.Text(): 世
bs.Text(): 界
bs.Text(): !
*/