C语言 | 文件操作详解与实战示例
🧩 C语言 | 文件操作详解与实战示例
✍️ 作者:凡间的八戒
🗓️ 时间:2025-11-12
🏷️ 标签:C语言、文件操作、IO流、fopen、fread、feof、ferror
🧠 前言
在 C 语言学习中,“文件操作”是非常关键的部分。
它赋予程序数据持久化的能力,让我们从屏幕输入输出走向真实的数据存储。
本文将带你全面掌握文件操作的核心内容,包含:
- 文件概念与类型
- 打开与关闭
- 文本与二进制存储方式
- 顺序/随机读写
- 缓冲区机制
- feof 与 ferror 的区别(重点)
一、为什么使用文件?
内存中的数据是临时的,程序退出后会被清除。
若想让数据长期保存,就必须将其写入磁盘文件。
📘 例如:
- 游戏存档
- 程序日志
- 用户配置
这些都是通过文件实现数据持久化的典型场景。
二、什么是文件?
在程序设计中,文件分为两类:
| 类型 | 说明 |
|---|---|
| 程序文件 | 存放源代码(.c)、目标文件(.obj)、可执行文件(.exe) |
| 数据文件 | 存放程序运行时需要读写的数据 |
三、文本文件与二进制文件
| 文件类型 | 存储形式 | 可读性 | 示例 |
|---|---|---|---|
| 文本文件 | ASCII 编码 | 可直接阅读 | .txt |
| 二进制文件 | 内存原始格式 | 不可直接阅读 | .bin |
📘 示例:
#include <stdio.h>int main() {int a = 10000;FILE* pf = fopen("test.txt", "wb");fwrite(&a, 4, 1, pf); // 二进制写入fclose(pf);return 0;
}
四、文件的打开与关闭
打开与关闭函数
FILE* fopen(const char* filename, const char* mode);
int fclose(FILE* stream);
打开模式速查表
| 模式 | 含义 | 文件不存在时 |
|---|---|---|
| “r” | 只读文本 | 出错 |
| “w” | 只写文本 | 新建 |
| “a” | 追加写文本 | 新建 |
| “rb” | 只读二进制 | 出错 |
| “wb” | 只写二进制 | 新建 |
| “ab” | 追加二进制 | 新建 |
| “r+” | 读写文本 | 出错 |
| “w+” | 读写文本(重建) | 新建 |
📘 示例:
#include <stdio.h>
int main() {FILE* pFile = fopen("myfile.txt", "w");if (pFile != NULL) {fputs("fopen example", pFile);fclose(pFile);}return 0;
}
五、文件的顺序读写
| 函数 | 功能 |
|---|---|
| fgetc | 读取单个字符 |
| fputc | 写入单个字符 |
| fgets | 读取一行 |
| fputs | 写入一行 |
| fscanf | 格式化读取 |
| fprintf | 格式化输出 |
| fread | 二进制读取 |
| fwrite | 二进制写入 |
📘 这些函数既可用于文件,也可用于标准流(stdin/stdout)。
六、文件的随机读写
fseek:移动文件指针
fseek(FILE* stream, long offset, int origin);
ftell:返回当前位置
long ftell(FILE* stream);
rewind:返回文件头
rewind(FILE* stream);
📘 示例:
#include <stdio.h>
int main() {FILE* pFile = fopen("example.txt", "wb");fputs("This is an apple.", pFile);fseek(pFile, 9, SEEK_SET);fputs(" sam", pFile);fclose(pFile);return 0;
}
七、文件读取结束的判断(重点)
在文件操作中,经常要判断文件是否读取完毕或发生错误。
这就需要使用 feof() 与 ferror() —— 它们看似相似,实则完全不同!
🧩 点击展开 | feof() 与 ferror() 的区别详解
🔹 feof —— 判断是否到达文件末尾
int feof(FILE *stream);
- 当上一次读操作到达文件结尾时返回非0。
- 必须先读取再判断,否则不会触发。
📘 错误示例:
while (!feof(fp)) { // ❌ 会多读一次fscanf(fp, "%d", &x);printf("%d\n", x);
}
📘 正确写法:
while (fscanf(fp, "%d", &x) == 1)printf("%d\n", x);if (feof(fp))printf("文件读取完毕\n");
🔹 ferror —— 判断是否发生读写错误
int ferror(FILE *stream);
- 当发生 磁盘错误、权限不足或设备异常 时返回非0。
📘 示例:
FILE* fp = fopen("test.txt", "r");
if (!fp) {perror("打开失败");return 1;
}int c;
while ((c = fgetc(fp)) != EOF)putchar(c);if (ferror(fp))puts("❌ 文件读写错误!");
else if (feof(fp))puts("✅ 文件正常结束。");fclose(fp);
🔹 区别总结表
| 函数 | 判断内容 | 触发时机 | 用途 | 是否自动清除 |
|---|---|---|---|---|
| feof | 到达文件尾 | 读到EOF后 | 判断读取结束 | 否 |
| ferror | 发生错误 | I/O异常后 | 判断设备问题 | 否 |
📘 可使用:
clearerr(FILE* stream);
清除错误与EOF状态。
🔹 对比示例
#include <stdio.h>
int main(void) {FILE* fp = fopen("demo.txt", "r");if (!fp) {perror("文件打开失败");return 1;}int c;while ((c = fgetc(fp)) != EOF)putchar(c);if (ferror(fp))printf("读取错误!\n");else if (feof(fp))printf("文件读取完毕。\n");fclose(fp);return 0;
}
🧠 总结一句话:
feof() 判断文件是否读完;
ferror() 判断是否出错;
二者互不替代,千万别混淆!
八、文件缓冲区机制
C语言使用缓冲文件系统来提升读写性能。
写入时数据先进入缓冲区,待缓冲满或 fflush() / fclose() 调用后才真正写入磁盘。
📘 示例:
#include <stdio.h>
#include <windows.h>int main() {FILE* pf = fopen("test.txt", "w");fputs("abcdef", pf);printf("睡眠10秒,此时文件内容未写入。\n");Sleep(10000);fflush(pf);printf("刷新缓冲区后写入成功。\n");fclose(pf);return 0;
}
九、总结与学习建议
✅ 核心要点:
- 文件操作基本步骤:
fopen → 读写 → fclose - 文本与二进制的本质区别在于存储形式
- 判断结束不要直接用
feof() - 养成使用
fflush()或fclose()的好习惯
💡 建议练习:
- 设计一个“学生成绩保存系统”;
- 用
fseek()实现随机修改; - 手动触发 I/O 错误测试
ferror()。
