程序里的数据,如果只放在内存里,一旦程序退出、内存回收,就再也找不回来了。想让这些「回忆」被永久保存,就要把它们写进文件。
程序文件与数据文件
从功能上看,文件分两种:
程序文件:源程序(.c)、目标文件(.obj)、可执行程序(.exe)。
数据文件:程序运行时真正读写的数据,比如运行的输出或要读取的内容。
一个文件名由路径 + 主干 + 后缀组成,比如 C:\code\test.txt。
文本文件 vs 二进制文件
按数据的组织形式,又分这两类:如果按 ASCII 形式存在外存就是文本文件(记事本打开能看懂),如果直接按二进制存储、不做转换就是二进制文件(记事本打开看不懂)。
// 整数 10000
// ASCII 存储:'1''0''0''0''0' → 占 5 字节
// 二进制存储:00 00 27 10 → 占 4 字节(小端:10 27 00 00)
流与 FILE 指针
为了屏蔽各种外部设备的差异,C 语言抽象出了「流」的概念。程序启动时默认打开三个标准流:stdin、stdout、stderr,类型都是 FILE*。
打开文件时系统会自动创建一个 FILE 结构并填充信息,我们只需一个 FILE* 来维护它。
打开与关闭
FILE* fp = fopen("data.txt", "w"); // "w" 只写;还有 r / a / + 等模式
if (fp == NULL) { perror("fopen"); return 1; }
// ...读写操作...
fclose(fp); // 关闭时也会刷新缓冲区
fp = NULL;
顺序读写的一串函数
| 函数 | 用途 |
|---|---|
fgetc / fputc | 读写单个字符 |
fgets / fputs | 读写一行文本 |
fscanf / fprintf | 格式化输入 / 输出 |
fread / fwrite | 二进制读写数据块 |
sscanf / sprintf | 从字符串提取 / 写成字符串 |
还有一对判断小帮手:feof(是否到文件结尾)和 ferror(是否读取出错)。
随机读写:指针想去哪儿就去哪儿
fseek(fp, 6, SEEK_SET); // 从文件开头偏移 6
// origin:SEEK_SET 开头 / SEEK_CUR 当前位置 / SEEK_END 末尾
ftell(fp); // 查当前偏移量
rewind(fp); // 回到开头(= fseek(fp, 0, SEEK_SET))
文件缓冲区:写进去不等于落盘
数据不是每次都立刻写进磁盘,而是先进入内存里的文件缓冲区,装满(或换行、或程序结束)才一起送出去。所以写完记得
fclose,中途要确保落盘可以用fflush(fp)强制刷新。
fputs("abcdef", fp); // 还没有真正写进磁盘
fflush(fp); // 强制刷新 → 数据落盘
更新文件:r+ / w+ / a+
- r+:保留内容,可定位覆盖,文件不存在则打开失败。
- w+:清空内容、从头写,文件不存在自动新建。
- a+:保留内容,默认在文件末尾追加,适合记日志。
一个小提醒:读写切换前,记得 fflush 或 fseek / rewind 重新定位,避免读到「旧位置」。
✿ 摘要
- 文件让数据永久保存,分程序文件 / 数据文件、文本 / 二进制文件。
- 通过流操作文件,
FILE*维护文件信息区。 fopen打开、fclose关闭;fseek/ftell/rewind随机定位。- 数据先进入缓冲区,用
fflush/fclose确保落盘。 - 更新模式
r+ / w+ / a+分别对应保留覆盖、清空重写、末尾追加。
愿当下的花如你所见般美丽
评论交流
欢迎留下你的想法