流式处理大型文件
处理文件而不全部载入内存
流式处理大型文件 是 CoddyKit 上的免费 Go Academy 课时。 这是第 4 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Go Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Go Academy 课程共包含 4 节课。
全部加载的问题
使用 os.ReadFile 将数 GB 的文件读入内存,可能会耗尽 RAM。相反,请对其进行流式处理:数据到达时就处理数据块。
流式处理的概念
流式处理意味着每次只在内存中保留一个很小的数据窗口。结合缓冲后,即使输入大小任意,也可以使用固定的内存进行处理。
使用 Scanner 逐行处理
对于文本,在读取器上使用 bufio.Scanner,可以一次处理一行,而不受文件大小影响。这里我们使用 strings.Reader 模拟一个文件。
package main
import (
"bufio"
"fmt"
"strings"
)
func main() {
src := strings.NewReader("alpha\nbeta\ngamma")
s := bufio.NewScanner(src)
for s.Scan() {
fmt.Println("processed:", s.Text())
}
}无需全部加载即可统计
您可以在几乎不占用内存的情况下,对巨大的数据流计算统计信息。
package main
import (
"bufio"
"fmt"
"strings"
)
func main() {
s := bufio.NewScanner(strings.NewReader("a\nbb\nccc"))
total := 0
for s.Scan() {
total += len(s.Text())
}
fmt.Println("total chars:", total)
}固定大小的数据块
对于二进制数据,请使用 Read 将数据读入固定大小的缓冲区。n 会告诉您填入了多少个字节。
package main
import (
"fmt"
"io"
"strings"
)
func main() {
src := strings.NewReader("0123456789")
buf := make([]byte, 4)
for {
n, err := src.Read(buf)
if n > 0 {
fmt.Printf("chunk: %s\n", buf[:n])
}
if err == io.EOF {
break
}
}
}使用 io.Copy 进行流式处理
io.Copy(dst, src) 使用一个较小的内部缓冲区,将读取器中的所有内容流式传输到写入器,而不会将全部内容加载到内存中。
package main
import (
"io"
"os"
"strings"
)
func main() {
src := strings.NewReader("streamed straight through\n")
io.Copy(os.Stdout, src)
}组合读取器和写入器缓冲区
将两端都包装在 bufio 中,即可高效地进行流式转换:带缓冲读取、处理、带缓冲写入,然后刷新。
package main
import (
"bufio"
"os"
"strings"
)
func main() {
r := bufio.NewScanner(strings.NewReader("one\ntwo"))
w := bufio.NewWriter(os.Stdout)
defer w.Flush()
for r.Scan() {
w.WriteString(r.Text() + "!\n")
}
}固定内存使用保证
由于缓冲区大小固定,无论输入是 1KB 还是 1TB,内存使用量都保持稳定。这是流式处理的关键优势。
避免常见错误
- 不要对巨大文件调用
os.ReadFile - 在检查错误之前,始终先处理
n个字节 - 记得刷新带缓冲的写入器:
Flush()
转换数据流
这里我们在每行数据经过流处理时将其转换为大写,每次只在内存中保留一行。
package main
import (
"bufio"
"os"
"strings"
)
func main() {
s := bufio.NewScanner(strings.NewReader("hi\nthere"))
w := bufio.NewWriter(os.Stdout)
defer w.Flush()
for s.Scan() {
w.WriteString(strings.ToUpper(s.Text()) + "\n")
}
}何时进行流式处理
当输入大小较大或未知,或者可以增量处理时,请使用流式处理。只有对于较小且有明确上限、需要一次性获取全部内容的数据,才应完整加载。
快速检查
测试您对流式处理的了解。
回顾
您已经学会了如何在不全部加载数据的情况下处理大型数据。
- 使用 Scanner 逐行处理文本
- 使用固定大小的
Read读取二进制数据块 - 使用
io.Copy进行流到流的传输 - 为两端添加缓冲,刷新写入器,并保持固定的内存使用量
常见问题解答
「流式处理大型文件」课时是免费的吗?
是的 — 「流式处理大型文件」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Go Academy 课程的其余内容,请升级到 CoddyKit PRO。 Go Academy 课程共包含 4 节课。
「流式处理大型文件」这节课中我会学到什么?
处理文件而不全部载入内存 你通过在浏览器中直接运行的动手代码来练习 Go Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 Go Academy 需要有经验吗?
无需任何先前经验。CoddyKit 上的 Go Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 4 节课,共 4 节。
「流式处理大型文件」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 Go Academy 课中编写并运行代码吗?
能。每节 Go Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。