Golang中io.Reader和io.Writer接口的核心作用是提供统一的读写行为抽象,使得文件、网络、内存等不同数据源可通过相同API操作,提升代码复用性、解耦性和可测试性,同时支持组合式I/O流处理。

Golang的
io
bufio
在Golang中,处理数据读写主要围绕
io.Reader
io.Writer
io.Reader
Read([]byte) (n int, err error)
io.Writer
Write([]byte) (n int, err error)
实际操作中,我们通常会这样使用它们:
package main
import (
"bytes"
"fmt"
"io"
"os"
"strings"
"bufio"
)
func main() {
// --- io.Reader 示例 ---
// 从字符串读取
r := strings.NewReader("Hello, Golang io!")
buf := make([]byte, 8) // 缓冲区大小
fmt.Println("--- io.Reader 读取示例 ---")
for {
n, err := r.Read(buf)
if err == io.EOF {
break // 读取到文件末尾
}
if err != nil {
fmt.Println("读取错误:", err)
return
}
fmt.Printf("读取了 %d 字节: %s\n", n, string(buf[:n]))
}
// --- io.Writer 示例 ---
// 写入到 bytes.Buffer
var b bytes.Buffer
w := &b // bytes.Buffer 实现了 io.Writer
fmt.Println("\n--- io.Writer 写入示例 ---")
message := "这是要写入的数据。"
n, err := w.Write([]byte(message))
if err != nil {
fmt.Println("写入错误:", err)
return
}
fmt.Printf("写入了 %d 字节。当前Buffer内容: %s\n", n, b.String())
// --- bufio.Reader 示例 ---
fmt.Println("\n--- bufio.Reader 缓冲读取示例 ---")
// 从字符串创建 bufio.Reader
br := bufio.NewReader(strings.NewReader("Line 1\nLine 2\nLine 3"))
for {
line, err := br.ReadString('\n') // 读取直到换行符
if err == io.EOF {
fmt.Printf("读取到文件末尾,最后一行: %s\n", line) // EOF时可能还有未处理的数据
break
}
if err != nil {
fmt.Println("bufio 读取错误:", err)
return
}
fmt.Printf("读取到行: %s", line)
}
// --- bufio.Writer 示例 ---
fmt.Println("\n--- bufio.Writer 缓冲写入示例 ---")
// 创建一个文件用于写入
file, err := os.Create("output.txt")
if err != nil {
fmt.Println("创建文件错误:", err)
return
}
defer file.Close() // 确保文件关闭
bw := bufio.NewWriter(file) // 将文件包装成 bufio.Writer
_, err = bw.WriteString("这是通过缓冲写入的第一行。\n")
if err != nil {
fmt.Println("bufio 写入错误:", err)
return
}
_, err = bw.WriteString("这是第二行,内容会先进入缓冲区。\n")
if err != nil {
fmt.Println("bufio 写入错误:", err)
return
}
// 此时数据可能还在缓冲区,需要手动Flush或缓冲区满时自动Flush
fmt.Println("数据已写入缓冲区,但可能未写入文件。")
err = bw.Flush() // 强制将缓冲区内容写入底层 io.Writer
if err != nil {
fmt.Println("Flush 错误:", err)
return
}
fmt.Println("缓冲区内容已Flush到文件。")
// 检查文件内容 (可选)
content, _ := os.ReadFile("output.txt")
fmt.Printf("output.txt 内容:\n%s", string(content))
}这段代码展示了
io.Reader
io.Writer
bufio.Reader
bufio.Writer
bufio
io.Reader
io.Writer
立即学习“go语言免费学习笔记(深入)”;
io.Reader
io.Writer
简单来说,
io.Reader
io.Writer
Read
Write
os.File
net.Conn
bytes.Buffer
strings.Reader
io.Copy(dst io.Writer, src io.Reader)
Reader
Writer
bytes.Buffer
strings.Reader
bytes.Buffer
Writer
gzip.Reader
io.Reader
bufio.Reader
io.Reader
os.File
io.Reader
举个例子,假设你有一个函数需要从某个地方读取配置:
func readConfig(r io.Reader) ([]byte, error) {
return io.ReadAll(r) // io.ReadAll 接受任何 io.Reader
}
// 调用时可以传入文件
// file, _ := os.Open("config.json")
// defer file.Close()
// configData, _ := readConfig(file)
// 也可以传入字符串
// configData, _ := readConfig(strings.NewReader(`{"key": "value"}`))这种设计思想,在我看来,是Go语言在工程实践中保持代码简洁、高效和可维护性的一个重要体现。
我们为什么需要缓冲I/O?这其实是个性能问题。想象一下,你正在写一封信,每写一个字就跑到邮局寄一次,然后再回来写下一个字。这效率是不是非常低?计算机的I/O操作也类似。每次对文件或网络进行读写操作,都可能涉及到系统调用。系统调用是用户态程序与内核态之间的一次上下文切换,这个过程是相对昂贵的。如果你的程序频繁地进行小块数据的读写,每次都触发系统调用,那么性能开销会非常大。
这就是缓冲I/O存在的意义。
bufio
io.Reader
io.Writer
bufio.Reader
bufio.Reader
io.Reader
bufio.Writer
bufio.Writer
io.Writer
bufio.Writer
Flush()
Close()
io.Writer
bufio
NewReader(r io.Reader)
NewWriter(w io.Writer)
io.Reader
io.Writer
NewReaderSize
NewWriterSize
我个人在使用
bufio
ReadString('\n')WriteString
Flush()
// 缓冲读取示例 (假设从一个文件中读取)
func bufferedReadExample(filePath string) {
file, err := os.Open(filePath)
if err != nil {
fmt.Println("打开文件失败:", err)
return
}
defer file.Close()
// 包装成带缓冲的Reader
br := bufio.NewReader(file)
fmt.Println("开始缓冲读取文件内容:")
for {
line, err := br.ReadString('\n') // 逐行读取
if err == io.EOF {
if len(line) > 0 { // 处理最后一行可能没有换行符的情况
fmt.Printf("最后一行 (EOF): %s", line)
}
break
}
if err != nil {
fmt.Println("读取错误:", err)
return
}
fmt.Printf("读取到: %s", line)
}
}
// 缓冲写入示例
func bufferedWriteExample(filePath string) {
file, err := os.Create(filePath)
if err != nil {
fmt.Println("创建文件失败:", err)
return
}
defer file.Close()
// 包装成带缓冲的Writer
bw := bufio.NewWriter(file)
// 写入多条小数据
for i := 0; i < 5; i++ {
_, err := bw.WriteString(fmt.Sprintf("这是第 %d 行数据。\n", i+1))
if err != nil {
fmt.Println("写入错误:", err)
return
}
}
// 此时数据可能还在内存缓冲区中,并未写入磁盘
fmt.Println("数据已写入缓冲区,等待Flush...")
// 强制将缓冲区内容写入底层文件
err = bw.Flush()
if err != nil {
fmt.Println("Flush错误:", err)
} else {
fmt.Println("数据已成功Flush到文件。")
}
}通过这种方式,
bufio
处理大文件和高并发网络I/O是Go语言的强项,但如果不正确使用
io
bufio
最佳实践:
defer file.Close()
defer conn.Close()
io.Closer
defer
defer
io.Copy
io.Reader
io.Writer
io.Copy(dst io.Writer, src io.Reader)
Read
Write
bufio
bufio.NewReader
bufio.NewWriter
io.EOF
io.Reader.Read
io.EOF
Read
io.EOF
n > 0
err == io.EOF
for {
n, err := r.Read(buf)
if n > 0 {
// 处理 buf[:n] 中的数据
}
if err == io.EOF {
break // 退出循环
}
if err != nil {
// 处理其他错误
return err
}
}bufio.Writer
Flush()
bufio.Writer
Flush()
Flush()
Close()
Flush()
net
net.Conn
io.Reader
io.Writer
bufio
常见陷阱:
bufio.Writer.Flush()
Flush
Close
io.Reader
Read
Read(p []byte) (n int, err error)
n
len(p)
Read
io.EOF
io.ReadFull
io.ReadAtLeast
n
len(p)
net.Conn
SetReadDeadline
SetWriteDeadline
io.ReadAll
io.ReadAll
io.Reader
总的来说,
io
bufio
以上就是Golang io库数据读写与缓冲处理的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号