bufio库通过缓冲机制减少系统调用,提升文件I/O性能。它在内存中开辟缓冲区,聚合零散读写操作,避免频繁的用户态与内核态切换。读取时,bufio.Reader一次性从磁盘读取大块数据到缓冲区,后续小读取操作直接从缓冲区获取;写入时,bufio.Writer先将数据暂存缓冲区,待缓冲区满或调用Flush()时才提交至操作系统。此“以空间换时间”策略显著降低开销,尤其适用于大文件或高频读写场景。实际使用中,推荐bufio.Scanner处理文本文件,按行或自定义分隔符读取;二进制数据则用reader.Read或writer.Write控制块大小。默认4KB缓冲区适用于多数场景,超大文件或高吞吐需求可增大缓冲区以进一步减少系统调用。关键陷阱包括:必须调用writer.Flush()确保数据落盘,否则程序崩溃会导致数据丢失;处理io.EOF时需先消费已读数据再退出;避免并发访问同一bufio实例,应为每个goroutine创建独立实例或加锁保护;始终使用defer file.Close()防止资源泄露。合理选择方法与缓冲区大小,并妥善处理错误,可使Go文件I/O兼具高效与稳定。

Golang的
bufio
在Go语言中,处理文件I/O时,我们往往会追求效率。没有
bufio
os.File
Read
Write
bufio
具体到实践,使用
bufio
文件读取:
立即学习“go语言免费学习笔记(深入)”;
我们首先需要打开一个文件,然后用
bufio.NewReader
Reader
package main
import (
"bufio"
"fmt"
"io"
"os"
)
func main() {
filePath := "example.txt"
// 创建一个示例文件,如果不存在的话
if _, err := os.Stat(filePath); os.IsNotExist(err) {
f, _ := os.Create(filePath)
f.WriteString("Hello, bufio!\n")
f.WriteString("This is a test line.\n")
f.WriteString("Another line for reading.\n")
f.Close()
}
file, err := os.Open(filePath)
if err != nil {
fmt.Println("Error opening file:", err)
return
}
defer file.Close() // 确保文件句柄被关闭
reader := bufio.NewReader(file) // 包装成带缓冲的Reader
fmt.Println("--- Reading file line by line ---")
for {
line, err := reader.ReadString('\n') // 读取直到遇到换行符
if err != nil {
if err == io.EOF {
fmt.Print(line) // 最后一行可能没有换行符,或者EOF前还有数据
break
}
fmt.Println("Error reading line:", err)
return
}
fmt.Print(line)
}
// 重新打开文件演示其他读取方式
file2, err := os.Open(filePath)
if err != nil {
fmt.Println("Error opening file:", err)
return
}
defer file2.Close()
reader2 := bufio.NewReader(file2)
fmt.Println("\n--- Peeking at next bytes ---")
peekedBytes, err := reader2.Peek(5) // 窥视接下来的5个字节,不移动读指针
if err != nil {
fmt.Println("Error peeking:", err)
return
}
fmt.Printf("Peeked: %s\n", string(peekedBytes))
// 再次读取,会从Peeked之后的位置开始
line2, _ := reader2.ReadString('\n')
fmt.Printf("Read after peek: %s", line2)
}这里我们使用了
reader.ReadString('\n')io.EOF
line
文件写入:
写入同样需要先打开文件(通常是
os.Create
os.OpenFile
bufio.NewWriter
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
filePath := "output.txt"
file, err := os.Create(filePath) // 创建或截断文件
if err != nil {
fmt.Println("Error creating file:", err)
return
}
defer file.Close() // 确保文件句柄被关闭
writer := bufio.NewWriter(file) // 包装成带缓冲的Writer
fmt.Println("--- Writing to file with bufio ---")
// 写入字符串
_, err = writer.WriteString("This is the first line written with bufio.\n")
if err != nil {
fmt.Println("Error writing string:", err)
return
}
// 写入字节切片
data := []byte("And this is the second line as bytes.\n")
_, err = writer.Write(data)
if err != nil {
fmt.Println("Error writing bytes:", err)
return
}
// 最关键的一步:将缓冲区中的数据真正写入文件
err = writer.Flush()
if err != nil {
fmt.Println("Error flushing writer:", err)
return
}
fmt.Println("Content written to", filePath, "successfully.")
// 验证写入内容
readAndPrintFile(filePath)
}
func readAndPrintFile(filePath string) {
file, err := os.Open(filePath)
if err != nil {
fmt.Println("Error opening file for verification:", err)
return
}
defer file.Close()
scanner := bufio.NewScanner(file)
fmt.Println("\n--- Verifying content of", filePath, "---")
for scanner.Scan() {
fmt.Println(scanner.Text())
}
if err := scanner.Err(); err != nil {
fmt.Println("Error during scan:", err)
}
}writer.Flush()
os.File
Flush()
Flush()
defer file.Close()
writer.Flush()
bufio
说到底,
bufio
bufio
bufio.Reader
bufio.Reader
bufio.Writer
Flush()
这种“以空间换时间”的策略,将多次小的、高开销的系统调用,合并成少数几次大的、低开销的系统调用,从而显著降低了I/O操作的整体延迟,提升了吞吐量。尤其是在处理大文件、网络流或者并发I/O密集型应用时,
bufio
bufio
选择合适的
bufio
读写方法的选择:
bufio.Scanner
bufio.Reader
scanner.Scan()
scanner.Text()
scanner.Split(bufio.ScanWords)
io.EOF
Scanner
reader.ReadString('\n')io.EOF
reader.ReadLine()
isPrefix
true
reader.Read(p []byte)
p
writer.WriteString(s string)
writer.Write(p []byte)
缓冲区大小的选择:
bufio.NewReader
bufio.NewWriter
bufio.NewReaderSize(r io.Reader, size int)
bufio.NewWriterSize(w io.Writer, size int int)
我的经验是,除非你通过基准测试(benchmarking)明确发现默认缓冲区是瓶颈,否则通常不需要特意去调整它。过大的缓冲区可能会占用不必要的内存,而过小的缓冲区则会削弱
bufio
bufio
bufio
忘记调用writer.Flush()
bufio.Writer
Flush()
Flush()
writer.Flush()
defer
Flush()
file, err := os.Create("output.txt")
if err != nil { /* handle error */ }
defer file.Close() // 确保文件关闭writer := bufio.NewWriter(file) defer writer.Flush() // 确保缓冲区内容被写入磁盘
// ... 写入操作 ...
io.EOF
reader.ReadString()
reader.ReadBytes()
io.EOF
line
io.EOF
io.EOF
for {
line, err := reader.ReadString('\n')
if len(line) > 0 { // 即使有EOF,也可能读取到数据
fmt.Print(line)
}
if err != nil {
if err == io.EOF {
break // 真正到达文件末尾
}
// 处理其他读取错误
fmt.Println("Error reading:", err)
return
}
}资源未关闭(文件句柄泄露): 虽然这不完全是
bufio
file.Close()
defer file.Close()
file, err := os.Open("input.txt")
if err != nil { /* handle error */ }
defer file.Close() // 确保文件关闭
// ... 使用bufio.Reader ...ReadLine()
isPrefix
reader.ReadLine()
line []byte
isPrefix bool
err error
isPrefix
true
line
ReadLine()
bufio.Scanner
reader.ReadString('\n')并发访问同一个bufio.Reader/Writer
bufio.Reader
bufio.Writer
bufio.Reader
bufio.Writer
bufio.Reader
bufio.Writer
os.File
os.File
sync.Mutex
bufio
sync.Mutex
正确地处理这些细节,能让你的Go文件I/O代码既高效又稳定。很多时候,代码的健壮性比单纯的性能优化更重要,毕竟一个会崩溃或丢失数据的程序,再快也没用。
以上就是Golang bufio库高效文件读取与写入的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号