os.OpenFile 使用 O_APPEND 时必须同时指定 O_WRONLY 或 O_RDWR,否则追加写入静默失败;Write 不接受 string,需用 io.WriteString、[]byte 转换或 fmt.Fprint;须检查 Write 返回的 n 值并处理部分写入;创建文件后必须检查 err 避免 nil 指针 panic。

os.OpenFile 用 O_APPEND 却没加 O_WRONLY,文件为空
Linux/macOS 下用 os.OpenFile 追加写入时,只传 os.O_APPEND | os.O_CREATE 是不够的。系统要求必须显式声明写权限,否则 Write() 或 bufio.Writer 看似成功(返回 nil 错误),实际数据根本没落盘,文件保持空。
正确做法是补上写模式:
-
os.O_WRONLY | os.O_APPEND | os.O_CREATE—— 只写 + 追加,最常用 -
os.O_RDWR | os.O_APPEND | os.O_CREATE—— 读写 + 追加,适合需后续读取的场景
Windows 上可能不报错,但跨平台代码必须统一按 POSIX 要求写全标志。
直接对 *os.File.Write 传 string,编译失败
*os.File.Write 的签名是 func (f *File) Write(b []byte) (n int, err error),它不接受 string。Go 不会在函数调用时自动把 string 转成 []byte,所以写 f.Write(msg) 会报错:cannot use msg (type string) as type []byte。
立即学习“go语言免费学习笔记(深入)”;
三种安全写法:
-
io.WriteString(f, msg)—— 推荐,语义清晰、内部已做字节转换和补全,错误处理直观 -
f.Write([]byte(msg))—— 轻量,但注意大字符串会复制底层数组,有内存开销 -
fmt.Fprint(f, msg)—— 适合带格式的输出,比如日志拼接,需import "fmt"
忽略 Write 返回的 n 值,导致部分写入未察觉
Write 和 WriteString 都返回 (n int, err error),其中 n 是实际写入字节数。在 NFS、满磁盘或信号中断等场景下,err 可能为 nil,但 n —— 数据只写了一半。
不能只检查 err:
- 用
io.WriteString可规避:它内部循环补全,确保全部写入或明确报错 - 若用
f.Write([]byte(msg)),应校验:if n != len(msg) { return io.ErrShortWrite } - 对关键数据(如配置、事务日志),写完后建议调用
f.Sync()确保落盘
os.Create 或 os.OpenFile 后没检查 err,后续 panic
os.Create 和 os.OpenFile 失败时,返回的 *os.File 是 nil,但错误不会自动传播。如果跳过 if err != nil 判断,直接对 nil 文件句柄调用 Write 或 Close,就会触发 panic: invalid memory address or nil pointer dereference。
必须立刻检查:
- 写法:
f, err := os.Create("x.txt"); if err != nil { return err },之后再defer f.Close() - 别用
if f == nil替代err != nil—— 某些系统调用失败时f可能非nil却不可用 - 权限错误(
permission denied)、路径不存在(no such file or directory)、fd 耗尽(too many open files)都走这个err路径,不是异常
最易被忽略的是:Write 返回的 n 和 err 必须一起看,尤其在非本地文件系统上;还有就是 O_APPEND 必须配写权限,这点在 Windows 开发时完全暴露不出来,一到 Linux 就静默失败。


















