【C语言程序设计】第35篇:文件的打开、关闭与读写操作

发布时间:2026/7/30 16:51:17

【C语言程序设计】第35篇:文件的打开、关闭与读写操作 1 引言文件操作的核心就是三步打开 → 读写 → 关闭。其中读写操作可以根据需求选择不同粒度的函数c#include stdio.h int main(void) { FILE *fp fopen(data.txt, w); if (fp NULL) return 1; /* 字符写入 */ fputc(A, fp); /* 字符串写入 */ fputs(Hello\n, fp); /* 格式化写入 */ fprintf(fp, 数字%d浮点数%.2f\n, 100, 3.14); fclose(fp); return 0; }本章我们将详细学习这些函数的用法和适用场景。2 文件的打开fopen2.1 函数原型c#include stdio.h FILE *fopen(const char *filename, const char *mode);功能打开指定文件返回文件指针参数filename文件名mode打开模式返回值成功返回FILE*失败返回NULL2.2 打开模式详解2.2.1 文本模式模式含义文件存在文件不存在r只读打开成功返回NULLw只写清空内容创建新文件a追加写入末尾创建新文件r读写打开成功返回NULLw读写清空内容创建新文件a读追加写入末尾创建新文件2.2.2 二进制模式在文本模式后加b表示二进制模式crb /* 二进制只读 */ wb /* 二进制只写清空 */ ab /* 二进制追加 */ rb /* 二进制读写 */ wb /* 二进制读写清空 */ ab /* 二进制读追加 */2.2.3 模式选择建议c/* 读取配置文件 */ FILE *fp fopen(config.ini, r); /* 写入日志追加 */ FILE *fp fopen(log.txt, a); /* 创建新文件覆盖旧文件 */ FILE *fp fopen(output.txt, w); /* 读取二进制文件如图片 */ FILE *fp fopen(image.jpg, rb); /* 需要同时读写同一个文件 */ FILE *fp fopen(data.bin, rb);2.3 打开失败的处理cFILE *fp fopen(data.txt, r); if (fp NULL) { perror(打开文件失败); /* 输出具体错误原因 */ /* 或 */ printf(无法打开文件请检查文件是否存在\n); return 1; }perror会根据全局变量errno输出错误描述如No such file or directory。3 文件的关闭fclose3.1 函数原型cint fclose(FILE *stream);功能关闭文件刷新缓冲区返回值成功返回0失败返回EOF3.2 为什么要关闭文件c#include stdio.h int main(void) { FILE *fp fopen(data.txt, w); if (fp NULL) return 1; fprintf(fp, 重要数据); /* 数据可能在缓冲区未写入磁盘 */ fclose(fp); /* 刷新缓冲区确保数据写入磁盘 */ return 0; }关闭文件的三个原因刷新缓冲区确保所有数据真正写入磁盘释放资源释放系统文件句柄操作系统限制同时打开的文件数防止数据损坏程序异常结束可能丢失缓冲区的数据3.3 忘记关闭的后果cvoid process_files(void) { for (int i 0; i 10000; i) { FILE *fp fopen(temp.txt, r); /* 处理文件... */ /* 忘记 fclose(fp) */ } } /* 可能耗尽系统文件句柄后续无法打开文件 */3.4 关闭后指针置空cfclose(fp); fp NULL; /* 防止悬空指针 */4 字符读写函数4.1 fgetc读取一个字符cint fgetc(FILE *stream);功能从文件中读取一个字符返回值成功返回读取的字符转为int失败或文件结束返回EOFc#include stdio.h int main(void) { FILE *fp fopen(data.txt, r); if (fp NULL) return 1; int ch; while ((ch fgetc(fp)) ! EOF) { putchar(ch); /* 输出到屏幕 */ } fclose(fp); return 0; }注意返回类型是int而不是char因为EOF通常是-1无法用char表示。4.2 fputc写入一个字符cint fputc(int c, FILE *stream);功能将一个字符写入文件返回值成功返回写入的字符失败返回EOFc#include stdio.h int main(void) { FILE *fp fopen(output.txt, w); if (fp NULL) return 1; for (char c A; c Z; c) { fputc(c, fp); } fputc(\n, fp); fclose(fp); return 0; }4.3 应用文件复制字符级c#include stdio.h int copy_file(const char *src, const char *dst) { FILE *fsrc fopen(src, r); if (fsrc NULL) return -1; FILE *fdst fopen(dst, w); if (fdst NULL) { fclose(fsrc); return -1; } int ch; while ((ch fgetc(fsrc)) ! EOF) { fputc(ch, fdst); } fclose(fsrc); fclose(fdst); return 0; } int main(void) { if (copy_file(source.txt, target.txt) 0) { printf(复制成功\n); } else { printf(复制失败\n); } return 0; }5 字符串读写函数5.1 fgets读取一行字符串cchar *fgets(char *str, int n, FILE *stream);功能从文件读取一行最多n-1个字符遇到换行符或文件结束停止特点会保留换行符如果读取到的话返回值成功返回str失败或文件结束返回NULLc#include stdio.h int main(void) { FILE *fp fopen(data.txt, r); if (fp NULL) return 1; char line[256]; while (fgets(line, sizeof(line), fp) ! NULL) { printf(读取到%s, line); /* line 可能包含换行符 */ } fclose(fp); return 0; }去除换行符cchar *p line; while (*p) { if (*p \n) { *p \0; break; } p; }5.2 fputs写入字符串cint fputs(const char *str, FILE *stream);功能将字符串写入文件特点不会自动添加换行符返回值成功返回非负数失败返回EOFc#include stdio.h int main(void) { FILE *fp fopen(output.txt, w); if (fp NULL) return 1; fputs(第一行\n, fp); fputs(第二行\n, fp); fputs(第三行, fp); /* 没有换行符 */ fclose(fp); return 0; }5.3 应用读取配置文件c#include stdio.h #include string.h #define MAX_LINE 256 void trim_newline(char *str) { size_t len strlen(str); if (len 0 str[len-1] \n) { str[len-1] \0; } } int main(void) { FILE *fp fopen(config.txt, r); if (fp NULL) { printf(配置文件不存在使用默认配置\n); return 0; } char line[MAX_LINE]; while (fgets(line, sizeof(line), fp) ! NULL) { trim_newline(line); /* 跳过空行和注释 */ if (line[0] \0 || line[0] #) { continue; } printf(配置项%s\n, line); } fclose(fp); return 0; }6 格式化读写函数6.1 fprintf格式化写入cint fprintf(FILE *stream, const char *format, ...);c#include stdio.h int main(void) { FILE *fp fopen(students.txt, r); if (fp NULL) return 1; char name[50]; int id; float score; int count 0; while (fscanf(fp, %s %d %f, name, id, score) 3) { printf(读取到%s %d %.1f\n, name, id, score); count; } printf(共读取 %d 条记录\n, count); fclose(fp); return 0; }6.3 应用学生成绩管理c#include stdio.h #include string.h #define MAX_STUDENTS 100 typedef struct { char name[50]; int id; float score; } Student; /* 保存数据到文件 */ int save_students(Student students[], int n, const char *filename) { FILE *fp fopen(filename, w); if (fp NULL) return -1; for (int i 0; i n; i) { fprintf(fp, %s %d %.1f\n, students[i].name, students[i].id, students[i].score); } fclose(fp); return 0; } /* 从文件读取数据 */ int load_students(Student students[], int *n, const char *filename) { FILE *fp fopen(filename, r); if (fp NULL) return -1; int count 0; while (count MAX_STUDENTS fscanf(fp, %s %d %f, students[count].name, students[count].id, students[count].score) 3) { count; } *n count; fclose(fp); return 0; } /* 打印学生列表 */ void print_students(Student students[], int n) { printf(\n学生列表\n); printf(姓名\t学号\t成绩\n); printf(----------------\n); for (int i 0; i n; i) { printf(%s\t%d\t%.1f\n, students[i].name, students[i].id, students[i].score); } } int main(void) { Student students[MAX_STUDENTS]; int n 0; /* 加载已有数据 */ if (load_students(students, n, students.txt) 0) { printf(已加载 %d 条记录\n, n); print_students(students, n); } /* 添加新学生 */ Student new_stu {赵六, 1004, 95.0}; students[n] new_stu; /* 保存数据 */ if (save_students(students, n, students.txt) 0) { printf(保存成功\n); } return 0; }7 三种读写方式的对比函数粒度适用场景特点fgetc/fputc字符逐字符处理、文本分析最灵活效率最低fgets/fputs字符串逐行处理配置文件、文本文件保留换行符安全可限制长度fprintf/fscanf格式化结构化数据的读写方便但效率较低可能有格式问题c/* 字符级逐字符复制 */ int ch; while ((ch fgetc(src)) ! EOF) { fputc(ch, dst); } /* 字符串级逐行处理 */ char line[256]; while (fgets(line, sizeof(line), fp) ! NULL) { /* 处理每一行 */ } /* 格式化读写结构化数据 */ fprintf(fp, %s %d %.2f\n, name, id, score); fscanf(fp, %s %d %f, name, id, score);8 常见错误与注意事项8.1 忘记检查文件指针cFILE *fp fopen(data.txt, r); fscanf(fp, %d, n); /* fp 可能为 NULL */8.2 混淆 r 和 wc/* r不会清空文件从开头读写 */ FILE *fp fopen(data.txt, r); /* w会清空文件 */ FILE *fp fopen(data.txt, w); /* 原有数据丢失 */8.3 fgets 缓冲区大小不足cchar buf[10]; fgets(buf, 10, fp); /* 最多读取9个字符 \0 */ /* 如果一行超过9个字符只读取前9个下次读取会继续 */8.4 fscanf 格式不匹配c/* 如果文件是 abc 100 */ fscanf(fp, %d, n); /* 失败%d 无法匹配 a */ /* 返回0n的值不变 */8.5 忘记关闭文件cFILE *fp fopen(log.txt, a); fprintf(fp, 日志信息\n); /* 忘记 fclose数据可能还在缓冲区 */8.6 对已关闭的文件操作cFILE *fp fopen(data.txt, r); fclose(fp); fgetc(fp); /* 错误使用已关闭的文件指针 */8.7 忽略 fscanf 返回值cfscanf(fp, %d, n); /* 没有检查返回值 */ if (fscanf(fp, %d, n) ! 1) { printf(读取失败\n); }9 本章小结本章系统介绍了文件的打开、关闭和三种读写方式1. 文件打开fopen2. 文件关闭fclose3. 字符级读写4. 字符串级读写5. 格式化读写6. 选择建议功能按格式将数据写入文件用法与printf完全类似只是多了一个文件指针参数返回值成功返回写入的字符数失败返回负数c#include stdio.h typedef struct { char name[50]; int id; float score; } Student; int main(void) { Student students[] { {张三, 1001, 88.5}, {李四, 1002, 92.0}, {王五, 1003, 78.5} }; int n 3; FILE *fp fopen(students.txt, w); if (fp NULL) return 1; for (int i 0; i n; i) { fprintf(fp, %s %d %.1f\n, students[i].name, students[i].id, students[i].score); } fclose(fp); return 0; }6.2 fscanf格式化读取cint fscanf(FILE *stream, const char *format, ...);功能按格式从文件中读取数据用法与scanf完全类似返回值成功匹配并赋值的个数文件结束返回EOF多种模式r、w、a及读写组合二进制模式加b总是检查返回值是否为NULL必须调用确保缓冲区刷新释放系统资源关闭后指针置空fgetc读取一个字符返回intfputc写入一个字符适合逐字符处理fgets读取一行安全有长度限制保留换行符fputs写入字符串不自动添加换行符适合逐行处理文本文件fprintf格式化写入类似printffscanf格式化读取类似scanf适合结构化数据读写注意检查返回值简单复制 →fgetc/fputc文本逐行处理 →fgets/fputs结构化数据 →fprintf/fscanf

相关新闻