05_标准库文件与项目实践
Go 文件与 JSON 标准库、模块结构、测试工具和交付流程。
Go 标准库、文件与项目实践
学习目标:使用标准库处理文件与 JSON,建立可测试的模块结构,并清楚区分语言示例和可交付服务。
1. 文件与资源关闭
os.Open 成功后才注册 defer file.Close();读取大文件宜使用扫描或缓冲,不要随意 os.ReadFile 全部放进内存。bufio.Scanner 默认 token 大小有限,大行输入要调整缓冲或改用 bufio.Reader,并在循环后检查 scanner.Err()。
func countLines(path string) (int, error) {
file, err := os.Open(path)
if err != nil { return 0, err }
defer file.Close()
scanner := bufio.NewScanner(file)
count := 0
for scanner.Scan() { count++ }
if err := scanner.Err(); err != nil { return 0, err }
return count, nil
}
这是函数片段,需要导入 bufio、os。关闭文件也可能失败,特别是写入文件时;关键写入要检查 Close 或 Sync 的错误,而不是认为 defer 已保证成功落盘。
2. JSON 与结构体标签
encoding/json 只处理导出的字段。外部 JSON 来自不可信边界,解码后仍要校验长度、范围与跨字段规则。默认未知字段会被忽略;严格 API 可在 json.Decoder 上启用 DisallowUnknownFields。不要把数据库实体直接序列化为公开响应,避免意外输出内部字段。
type NoteResponse struct {
ID int64 `json:"id"`
Title string `json:"title"`
Version int64 `json:"version"`
}
json:"-" 可排除字段,但公开 DTO 应从一开始就只包含允许输出的内容。时间字段在 API 契约中写明格式与时区,通常使用带时区的 ISO 8601/RFC 3339 字符串。
3. 项目目录与依赖方向
小项目可从 main.go、store.go、handlers.go 和对应 _test.go 起步;随着功能增长再拆 cmd/api、internal/service、internal/store。internal 限制目录外包导入,适合应用内部实现。包之间避免循环依赖;HTTP handler 依赖业务接口,业务规则不直接依赖 http.ResponseWriter。
关键原则:接口应放在需要抽象的调用方附近。只有一种实现且没有替换需求时,先使用具体类型;测试可以从纯函数和真实临时资源开始,不必对所有依赖做 Mock。
4. 测试、工具与交付
go test ./... 验证行为,go test -race ./... 检查实际测试路径的数据竞争,go vet ./... 查静态可疑点,go fmt ./... 统一格式。CI 在干净环境重新下载依赖、运行测试并构建;不要依赖本机缓存里的未记录包。
练习:给 countLines 写临时文件测试,覆盖空文件、三行、文件不存在和超长一行;然后把它暴露为一个命令行子命令,并写清退出码。