判断空文件还是读取失败应以err是否为nil为准:os.Stat显示size==0是合法空文件,而权限拒绝、路径不存在等必返回非nil错误;忽略err仅凭len(buf)==0或scanner.Scan()返回false判断会导致误判。

os.Open 返回 nil 文件指针 + 非 nil 错误时,后续调用 Read 必然 panic;空文件(长度为 0)本身不是错误,但容易被误判为读取失败——关键在区分「空内容」和「读取异常」。
如何判断是空文件还是读取失败
空文件(os.Stat 返回 size == 0)是合法状态,os.ReadFile 或 bufio.Scanner 都能正常返回空字节切片或 false,不报错;而读取失败(如权限拒绝、路径不存在)一定伴随非 nil 的 err。
常见混淆点:
- 用
len(buf) == 0判断「没读到数据」,却忽略err != nil—— 这会把permission denied当成空文件处理 -
scanner.Scan()返回false时,必须紧接着检查scanner.Err(),否则无法区分 EOF 和 I/O 错误 -
io.ReadFull对空文件直接返回io.ErrUnexpectedEOF,这不是io.EOF,需单独处理
os.ReadFile 读空文件是否安全
os.ReadFile 对空文件完全安全:它返回 []byte{} 和 nil 错误,无需额外分支。但要注意——
- 它仍会触发底层
open和stat系统调用,所以路径不存在、权限不足等错误照常返回,不能因为「返回了空切片」就认为成功 - 若业务逻辑要求「非空配置文件」,应在读取后显式检查
len(data) == 0并返回自定义错误,例如:if len(data) == 0 { return fmt.Errorf("config file is empty") } - 不要用
os.IsNotExist检查空文件:空文件存在且可读,os.IsNotExist一定为false
写入空内容时如何避免静默丢弃错误
写空字符串("")或空切片([]byte{})本身不会出错,但 file.Write 或 io.WriteString 成功只表示写入缓冲区,真正落盘靠 Close。
容易踩的坑:
- 只检查
Write的err,忽略Close可能返回的磁盘满、只读文件系统等错误 - 用
os.WriteFile写空内容时,若父目录不存在,仍会报no such file or directory—— 它不是原子的「路径+写入」,只是原子的「写入」 - 写入后立即
os.Stat检查大小,可能因缓存未刷盘得到旧值;应依赖Close错误或syscall.Sync强制刷盘
bufio.Scanner 处理空行与空文件的边界情况
bufio.Scanner 默认跳过空行,且对空文件直接返回 false 而不触发 Err(),这容易让人误以为「没数据=没问题」。
真实场景中需主动确认:
- 循环前先调用一次
scanner.Scan(),若返回false,立刻检查scanner.Err();如果是nil,说明是空文件或纯空行 - 若需保留空行,改用
bufio.Reader.ReadString('\n')或ReadBytes('\n'),它们对空行返回"\n"和nil错误 - 扫描 CSV 或 JSON 行时,空行可能导致解析器卡住或 panic,建议前置过滤:
strings.TrimSpace(line) == ""时跳过
空文件本身无害,真正危险的是把「读不到内容」和「读取过程出错」混为一谈——所有判断都必须从 err 出发,而不是从数据长度或 scanner 返回值出发。


















