楼层: 首页/ 软件技术/ C 语言/ 文件 IO:让数据活过程序这次运行
8

文件 IO:让数据活过程序这次运行

File I/O with FILE*

程序一关,变量全没。想把成绩、配置存下来下次还能读,就得写文件。C 的文件操作核心是一个 FILE* 指针——"先打开,读/写,最后关上",三步曲。

打开与关闭:fopen / fclose

fopen 的模式(mode)怎么选
模式含义
"r"只读,文件必须已存在。
"w"只写,文件不存在就新建,存在就清空(小心!)。
"a"追加,在文件末尾接着写,不清空旧内容。
"r+"读写,文件须存在,不清空。
加 b(如 "rb")二进制模式,处理图片/视频等非文本文件时用。

写文件再读回来(文本模式)

#include <stdio.h> int main() { // 1. 打开(写模式) FILE *fp = fopen("score.txt", "w"); if (fp == NULL) { // 打不开(路径错/没权限)要判空 perror("打开失败"); return 1; } // 2. 写入:fprintf 和 printf 几乎一样,只是多了 fp fprintf(fp, "小明 %d %.1f\n", 18, 92.5); fclose(fp); // 3. 用完必须关! // 重新以读模式打开 fp = fopen("score.txt", "r"); char name[20]; int age; double score; fscanf(fp, "%s %d %lf", name, &age, &score); // 注意 age、score 要传地址 printf("读回:%s 年龄%d 成绩%.1f\n", name, age, score); fclose(fp); return 0; }

运行结果

读回:小明 年龄18 成绩92.5

其余常用文件函数速查

函数用途
fgetc / fputc读写一个字符。
fgets / fputs读写一行字符串。读文本行用它,别用 gets。
fread / fwrite二进制读写整块数据(数组、结构体),最快。
fseek / ftell / rewind移动文件指针位置、查当前位置、回到开头。
stdin / stdout / stderr标准输入、标准输出、标准错误,三个默认打开的流。

错误处理:errno / perror / strerror 三件套

C 库函数出错时不抛异常,而是返回一个错误值(通常 -1 或 NULL),并把错误原因编号写进全局变量 errno。你要做的是:先看返回值,再读 errno 知道为啥错。

fopen 失败时的标准错误处理三件套

#include <errno.h> #include <string.h> #include <stdio.h> FILE *fp = fopen("not_exist.txt", "r"); if (fp == NULL) { // ① perror:直接把 errno 对应的人话打出来 perror("打开文件失败"); // 打印:打开文件失败: No such file or directory // ② errno 是个整数错误码 printf("错误码 = %d\n", errno); // 2(ENOENT) // ③ strerror(errno):拿到错误描述字符串,自己格式化用 printf("原因:%s\n", strerror(errno)); return 1; }
工具干什么
errno全局 int,出错时被库函数赋值。注意:成功调用不会清 0,所以要先看返回值错了再读 errno。
perror("前缀")一句话打印:前缀 + 冒号 + errno 对应描述。最省事。
strerror(errno)返回错误描述字符串,想自己拼日志就用它。
feof(fp) / ferror(fp)feof 判断是否读到了文件末尾;ferror 判断流是否出错。读文件循环别只靠 feof,要用 fread 的返回值判断是否读到数据。

防坑:① errno 是个"垃圾桶"——上一次的错误可能还留着,必须在函数返回错误后立刻读,中间别插别的库调用;② 读文件的正确姿势是 while ((n = fread(...)) > 0) {...},而不是 while(!feof(fp))(feof 要等读失败后才置位,会多读一次空)。