Go 标准库中的
bufio
包提供了带缓冲的读写功能,可以显著提高文件和数据处理效率。而bufio.Scanner
则是读取文本文件中每一行的利器,常用于日志、配置等文本处理场景。
一、为什么使用 bufio
?
直接对文件进行 os.File.Read()
或 os.File.Write()
操作是无缓冲的,每次调用都会进行系统调用,效率较低。
bufio
在内部使用内存缓冲区,减少与操作系统的交互,性能提升明显。
二、bufio.Reader
:带缓冲的读取
示例:读取文件内容并逐行输出
scss
file, err := os.Open("sample.txt")
if err != nil {
log.Fatal(err)
}
defer file.Close()
reader := bufio.NewReader(file)
for {
line, err := reader.ReadString('\n')
if err == io.EOF {
break
}
if err != nil {
log.Fatal(err)
}
fmt.Print(line)
}
方法说明:
- •
ReadString(delim byte)
:读到指定分隔符为止(如\n
)。 - •
ReadBytes(delim byte)
:与ReadString
类似,但返回字节切片。 - •
ReadLine()
:低级函数,建议用Scanner
替代。 - •
Peek(n int)
:读取但不消费前n
个字节。
三、bufio.Writer
:带缓冲的写入
css
file, _ := os.Create("output.txt")
defer file.Close()
writer := bufio.NewWriter(file)
writer.WriteString("Hello, buffered write!\n")
writer.Flush() // 必须显式刷新缓冲区
注意: 使用
bufio.Writer
写入数据后,需要调用Flush()
将数据写入底层文件或网络连接,否则可能数据不会立即写入。
四、bufio.Scanner
:按行或自定义分隔符扫描输入
1. 按行读取文本文件
css
file, _ := os.Open("sample.txt")
defer file.Close()
scanner := bufio.NewScanner(file)
for scanner.Scan() {
fmt.Println(scanner.Text())
}
if err := scanner.Err(); err != nil {
log.Fatal(err)
}
2. 自定义分隔符(如按空格、逗号、段落分隔)
css
scanner := bufio.NewScanner(strings.NewReader("go is simple. go is fast."))
// 自定义按单词分割
scanner.Split(bufio.ScanWords)
for scanner.Scan() {
fmt.Println(scanner.Text())
}
常见分割器:
- •
bufio.ScanLines
(默认) - •
bufio.ScanWords
- •
bufio.ScanBytes
五、Scanner 与大文件的关系
- •
Scanner
默认缓冲区大小为 64K,如需处理超大行文本,可以通过scanner.Buffer()
提高上限:
go
scanner.Buffer(make([]byte, 1024), 10*1024*1024) // 提升最大支持到10MB
六、小结
类型 | 功能 | 适合场景 |
---|---|---|
bufio.Reader |
提供高效逐行或按字节读取 | 网络流、日志、长行文本等 |
bufio.Writer |
高效写入并可缓冲 | 写文件、网络输出 |
bufio.Scanner |
方便读取行、单词等小粒度内容 | 配置文件、日志文件、终端输入 |
七、建议实践练习
-
- 写一个程序,读取大文件并统计每一行的字符数。
-
- 模拟 tail -f,持续从文件末尾读取新增内容。
-
- 实现一个按单词频率排序的词频统计器。