fmt.Fprintf 将格式化字符串写入任意 io.Writer 接口实现对象,要求 Writer 实现 Write([]byte) (int, error),常见目标包括 os.Stdout、*os.File、bytes.Buffer 等;需避免 nil Writer、手动 Flush 缓冲、注意错误传播与生命周期管理。

fmt.Fprintf 的基本用法和 Writer 接口要求
fmt.Fprintf 的核心是把格式化后的字符串写入任意满足 io.Writer 接口的对象。它不关心你传的是文件、网络连接、内存缓冲区还是自定义类型,只要该类型实现了 Write([]byte) (int, error) 方法,就能用。
常见能直接传的包括:os.Stdout、os.Stderr、*os.File、bytes.Buffer、net.Conn、http.ResponseWriter(在 HTTP handler 中)。
- 别传
nil的Writer,否则会 panic:运行时错误panic: runtime error: invalid memory address or nil pointer dereference - 如果
Writer的Write方法返回非零错误(比如磁盘满、连接断开),fmt.Fprintf会原样返回该错误,不会吞掉 - 注意:它只做格式化 + 写入,**不自动 flush** —— 对于带缓冲的
Writer(如bufio.Writer),得手动调Flush()
写入 bytes.Buffer 用于测试或构造字符串
这是最常用的调试和构造场景。相比 fmt.Sprintf,fmt.Fprintf 避免了中间字符串分配,对大内容更友好。
Go 配置库,使用 spf13/viper — 分层优先级(flag > env >file > KV > default),提供 BindPFlag/BindPFlags、SetEnvPrefix + SetEnvKeyReplace 等功能。
var buf bytes.Buffer fmt.Fprintf(&buf, "user: %s, id: %d", "alice", 42) s := buf.String() // "user: alice, id: 42"
- 传地址
&buf,因为bytes.Buffer.Write是指针方法 - 如果反复使用同一个
buf,记得调buf.Reset()清空,而不是新建 - 不要用
buf.Bytes()直接取底层切片来修改 ——fmt.Fprintf可能触发扩容,导致指针失效
写入文件时的常见错误和权限处理
直接用 os.OpenFile 打开文件后传给 fmt.Fprintf 很常见,但容易忽略打开模式和错误检查。
- 写入前必须用
os.O_WRONLY或os.O_CREATE | os.O_APPEND等写权限打开,只读打开会返回*os.PathError错误:open xxx: permission denied - 别漏掉
defer f.Close(),否则可能丢失最后缓冲内容(尤其没显式Flush时) - 如果要追加写,确保用
os.O_APPEND;否则默认从文件开头覆盖写入 - 示例安全写法:
f, err := os.OpenFile("log.txt", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644) if err != nil { log.Fatal(err) } defer f.Close() fmt.Fprintf(f, "[%s] %s\n", time.Now().Format("15:04:05"), "request processed")
写入 http.ResponseWriter 时的注意事项
在 HTTP handler 中用 fmt.Fprintf(w, ...) 很方便,但要注意响应头和状态码已发送就不能再改。
- 一旦有内容被写入(哪怕只是空格或换行),
Header()和WriteHeader()就失效 —— 此时再调w.WriteHeader(http.StatusNotFound)会被忽略,且日志里会出现http: superfluous response.WriteHeader call - 如果需要控制状态码,务必在任何
fmt.Fprintf(w, ...)之前调用w.WriteHeader() - 避免在循环里频繁调用
fmt.Fprintf(w, ...)输出大量小片段 —— 可能触发多次 TCP 包,影响性能;可先拼到bytes.Buffer再一次性写入
真正麻烦的不是语法,而是 Writer 的生命周期和错误传播路径 —— 比如一个 net.Conn 在写一半时断开,fmt.Fprintf 返回的 error 可能被忽略,结果下游以为写成功了。

















