C语言 1000问 · 文件I/O Q3:怎么正确判断文件读完?为什么常说 while (!feof(fp)) 是错的?
来源:Flomo 原始笔记|查看原笔记|迁移日期:2026-10-31
C语言 1000问 · 文件I/O Q3:怎么正确判断文件读完?为什么常说 while (!feof(fp)) 是错的?
▎ 五大学习法:费曼学习法——把「feof 的坑」讲透
feof 到底是什么
- feof(fp) 不是「预测下一次读会不会到末尾」,它报告的是「上一次读是否因为碰到文件末尾而结束」。
- 它是「事后标记」:只有真正读到 EOF(且读到失败)之后,它才变真。
- 同理 ferror 报告上次读是否出错,也属事后。
while (!feof(fp)) 为什么错
- 错误写法:while (!feof(fp)) { fread(buf, …); process(buf); }
- 问题:读完最后一块时 feof 还是 false(这次读成功、没触发 EOF 标记),循环又进去一次;这一次 fread 读到 0 字节才置 EOF 标记。于是 process 拿着「上次的旧数据」多处理一遍。
- 更糟的是如果没检查 fread 返回值,就用了无效 / 陈旧数据。
正确写法
- 用读操作的返回值控制循环:
- while ((n = fread(buf, 1, sizeof buf, fp)) > 0) { process(buf, n); }
- 或 fgets:while (fgets(line, sizeof line, fp) != NULL) { … }
- 或 getc:int c; while ((c = getc(fp)) != EOF) { … }
- 判断「是否真出错」用 ferror,判断「正常读完」用 feof。
- 标准套路:先读,读到的元素数 < 期望时,再看 feof / ferror 区分「正常结束」还是「出错」。
几个相关坑
- getc 返回 int 不是 char(要用 EOF 区分),写成 char c = getc(…) 会把 0xFF 误判成 EOF。
- fgets 不保证读满一行:行太长会截断,要检查是否含 ‘\n’。
- 读一条记录(fread 结构体)要检查返回是否为 1(成功读一条),部分读取要处理。
一句话:feof 是「上次读是否因到末尾而结束」的事后标记,不能用来预测下一次;正确做法是「用读函数的返回值控制循环」,读完再用 feof / ferror 区分正常结束还是出错。
📎 问题库(专栏⑭导航)→ https://v.flomoapp.com/mine/?memo_id=MjQ1NzM0NTk5
📎 文件I/O Q2(缓冲)→ https://v.flomoapp.com/mine/?memo_id=MjU2NDUwNDQ5