Go Academy · 课时

带缓冲的读取器

使用 bufio 高效读取

第 1 / 4 课13 个步骤

带缓冲的读取器 是 CoddyKit 上的免费 Go Academy 课时。 这是第 1 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Go Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Go Academy 课程共包含 4 节课。

为什么要进行 Buffer 读取

从文件或网络一次读取一个字节,每次都会触发系统调用。这样很慢。

bufio 包装读取器,将数据分块读入内存中的缓冲区,再从该缓冲区为您的小量读取提供数据。

  • 系统调用更少
  • 处理大量小量读取时快得多

创建 bufio.Reader

使用 bufio.NewReader 包装任何 io.Reader。这里我们包装一个 strings.Reader。

package main

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

func main() {
	r := bufio.NewReader(strings.NewReader("Hello, Go!"))
	fmt.Printf("buffered reader ready: %T\n", r)
}

读取 Bytes

ReadByte 返回下一个字节。该字节来自缓冲区,而不是通过新的系统调用读取。

package main

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

func main() {
	r := bufio.NewReader(strings.NewReader("Go"))
	b1, _ := r.ReadByte()
	b2, _ := r.ReadByte()
	fmt.Printf("%c%c\n", b1, b2)
}

使用 ReadString 读取到分隔符

ReadString(delim) 读取数据,直到遇到分隔符字节的第一次出现,并返回包括分隔符在内的全部内容。

package main

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

func main() {
	r := bufio.NewReader(strings.NewReader("first,second,third"))
	part, _ := r.ReadString(',')
	fmt.Printf("%q\n", part)
}

预读后续内容

Peek(n) 返回接下来的 n 个字节,但不会消耗它们。在确定解析方式之前进行判断时非常有用。

package main

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

func main() {
	r := bufio.NewReader(strings.NewReader("HTTP/1.1"))
	head, _ := r.Peek(4)
	fmt.Printf("starts with: %s\n", head)
}

Buffer 大小

bufio.NewReaderSize(r, size) 设置缓冲区容量。缓冲区越大,底层读取次数越少,但占用的内存越多。

package main

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

func main() {
	r := bufio.NewReaderSize(strings.NewReader("data"), 4096)
	fmt.Println("buffer size:", r.Size())
}

ReadLine 与 ReadString

ReadString('\n') 会保留换行符;许多解析器更喜欢将其去除。Scanner 会自动处理这一点(下一课介绍)。

当您需要完全控制分隔符时,请使用 ReadString。

处理 io.EOF

底层流耗尽时,读取方法会返回 io.EOF。请始终检查它,以确定何时停止。

package main

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

func main() {
	r := bufio.NewReader(strings.NewReader("ab"))
	for {
		c, err := r.ReadByte()
		if err == io.EOF {
			break
		}
		fmt.Printf("%c", c)
	}
	fmt.Println()
}

使用 ReadRune 读取 Unicode

ReadRune 会解码完整的 UTF-8 符文,而一个符文可能跨越多个字节。对于包含非 ASCII 字符的文本,请使用它。

package main

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

func main() {
	r := bufio.NewReader(strings.NewReader("héllo"))
	for {
		ru, _, err := r.ReadRune()
		if err != nil {
			break
		}
		fmt.Printf("%c ", ru)
	}
	fmt.Println()
}

读取直到完成

一种常见模式是:使用 ReadString 循环读取直到 EOF,从而逐行处理流,同时保持精细的控制。

package main

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

func main() {
	r := bufio.NewReader(strings.NewReader("a\nb\nc\n"))
	for {
		line, err := r.ReadString('\n')
		fmt.Print("got: " + line)
		if err == io.EOF {
			break
		}
	}
}

何时使用 bufio.Reader

  • 包装较慢的数据源(文件、套接字)
  • 需要进行大量小量读取时
  • 需要预读,或按分隔符/符文读取时

对于简单的逐行扫描,请优先使用 bufio.Scanner(下一课介绍)。

快速检查

测试您对带缓冲读取器的理解。

回顾

您已经学会了 bufio.Reader 如何通过缓冲减少系统调用。

  • NewReader / NewReaderSize 包装一个 io.Reader
  • ReadByte、ReadRune、ReadString 从缓冲区提供数据
  • Peek 可以预读而不消耗数据
  • 遇到 io.EOF 时停止
免费开始

用 AI 导师学习 Go — 免费

在浏览器中编写并运行真实代码,获得全天候 AI 导师的即时帮助,并在网页或应用中继续学习。

课程
51
课程
203

常见问题解答

「带缓冲的读取器」课时是免费的吗?

是的 — 「带缓冲的读取器」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Go Academy 课程的其余内容,请升级到 CoddyKit PRO。 Go Academy 课程共包含 4 节课。

「带缓冲的读取器」这节课中我会学到什么?

使用 bufio 高效读取 你通过在浏览器中直接运行的动手代码来练习 Go Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 Go Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 Go Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 1 节课,共 4 节。

「带缓冲的读取器」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 Go Academy 课中编写并运行代码吗?

能。每节 Go Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 带缓冲的读取器
  2. 扫描器
  3. 带缓冲的写入器
  4. 流式处理大型文件
← 返回 Go Academy