文件基础操作详解
一、为什么使用文件?
核心问题:数据持久化存储
-
内存的局限性:
-
程序运行时数据存储在内存中
-
程序退出时内存被回收,数据丢失
-
无法保留历史数据
-
-
文件的优势:
-
数据存储在硬盘/磁盘上
-
程序关闭后数据依然保留
-
支持长期、持久化的数据存储
-
二、什么是文件?
文件分类(按功能分类)
- 程序文件
-
源程序文件(.c)
-
目标文件(.obj)
-
可执行文件(.exe)
- 数据文件
-
程序运行时需要从中读取数据的文件、输出内容的文件
-
本章重点讨论的对象
传统输入输出的局限性
-
输入对象:终端键盘
-
输出对象:显示器
-
无法实现数据的长期保存和重复使用
文件名
-
一个文件要有一个唯一的标识,以便用户识别和引用
-
文件标识 = 文件路径 + 文件主干名 + 文件后缀(文件的身份证)
-
为了方便起见,文件标识常被称为文件名
示例:C:\Users\Desktop\example.txt
三、二进制文件和文本文件(按内容分类)
数据存储方式对比
| 存储方式 | 特点 | 文件大小 | 可读性 |
|---|---|---|---|
| 二进制文件 | 直接以内存中的二进制形式存储 | 较小 | 不可直接阅读 |
| 文本文件 | 以ASCII码形式存储 | 较大 | 可直接阅读 |
存储示例
-
整数
10000的存储:-
二进制:
00100111 00010000(2字节) -
ASCII:
'1''0''0''0''0'(5字节)

-
注意:用文本编辑器打开二进制文件会显示乱码,因为文本编辑器会以ASCII的形式翻译二进制序列
四、流(Stream)的概念
什么是流?
流是C语言中一个重要的抽象概念,它就像一条"数据的河流",数据在这条河流中流动。这个设计让程序员能够用统一的方式来处理各种不同的输入输出设备。
为什么需要流?
计算机需要与各种外部设备交互:
-
输入设备:键盘、文件、网络等
-
输出设备:显示器、打印机、文件等
每种设备都有独特的操作方式,如果没有流的概念,程序员需要为每种设备编写特定代码,既繁琐又容易出错。
流的价值:提供统一抽象层,把所有输入输出设备都看作是"数据的河流",程序员只需要学会与"河流"打交道,而不需要关心具体设备细节。
流的操作流程
-
打开流 - 建立与数据源的连接
-
操作流 - 读取或写入数据
-
关闭流 - 断开连接,释放资源
标准流
C程序启动时自动打开三个标准流:
-
stdin- 标准输入流(通常为键盘) -
stdout- 标准输出流(通常为显示器) -
stderr- 标准错误流(通常为显示器)
五、文件指针
关键概念:文件类型指针
在C语言中,我们通过**FILE***类型的文件指针来维护流的各种操作。这是缓冲文件系统中的核心概念。
文件信息区
-
每个打开的文件都会在内存中创建一个文件信息区
-
这个信息区是一个
FILE结构体变量,通常包含:-
文件名、文件状态
-
文件当前位置
-
缓冲区信息等
-
不同编译器对
FILE的具体定义略有差异
// VS2013中的FILE结构示例
struct _iobuf
{char *_ptr; // 缓冲区当前位置int _cnt; // 剩余字符数char *_base; // 缓冲区基地址int _flag; // 文件状态标志int _file; // 文件描述符int _charbuf; // 字符缓冲区int _bufsiz; // 缓冲区大小char *_tmpfname; // 临时文件名
};
typedef struct _iobuf FILE;
重要:作为使用者,我们不需要关心
FILE结构体的具体成员,系统会自动管理这些细节。
文件指针的作用
FILE* pf; // 创建一个文件指针变量
-
pf指向文件信息区 → 通过信息区访问实际文件
-
相当于文件的"遥控器",通过指针间接操作文件

文件操作流程
-
打开文件 → 打开流
-
操作文件 → 操作流
-
关闭文件 → 关闭流
文件指针贯穿整个操作过程,是连接程序与文件的桥梁。
六、文件的打开和关闭
文件操作函数
// 打开文件
FILE *fopen(const char *filename, const char *mode);// 关闭文件
int fclose(FILE *stream);
文件打开模式
| 模式 | 含义 | 文件要求 |
|---|---|---|
"r" | 只读 | 文件必须存在 |
"w" | 只写 | 创建新文件/清空已存在内容再写 |
"a" | 追加 | 创建新文件/在已有内容末尾添加 |
"r+" | 读写 | 文件必须存在 |
"w+" | 读写 | 创建新文件/清空已存在文件 |
"a+" | 读写 | 创建新文件/在已有文件末尾添加 |
二进制模式:在以上模式后加
b,如"rb"、"wb"
完整示例
#include <stdio.h>int main()
{FILE *pFile;// 打开文件 - 多种路径写法pFile = fopen("myfile.txt", "w"); // 当前目录pFile = fopen("C:/Users/Desktop/myfile.txt", "w"); // 绝对路径pFile = fopen("./../myfile.txt", "w"); // 相对路径// 检查文件是否打开成功if (pFile == NULL) {perror("fopen"); // 输出错误信息return -1;}// 文件操作...// 关闭文件fclose(pFile);pFile = NULL; // 防止野指针return 0;
}
七、文件的顺序读写
顺序读写函数分类
| 功能 | 函数名 | 适用流 |
|---|---|---|
| 字符输入 | fgetc | 所有输入流 |
| 字符输出 | fputc | 所有输出流 |
| 文本行输入 | fgets | 所有输入流 |
| 文本行输出 | fputs | 所有输出流 |
| 格式化输入 | fscanf | 所有输入流 |
| 格式化输出 | fprintf | 所有输出流 |
| 二进制输入 | fread | 文件 |
| 二进制输出 | fwrite | 文件 |
字符顺序读写示例
// 写字符到文件
for(int ch = 'a'; ch <= 'z'; ch++)
{fputc(ch, pFile);
}// 从文件读取字符
int ch = 0;
while((ch = fgetc(pFile)) != EOF)
{printf("%c ", ch);
}// 标准流使用
int ch = fgetc(stdin); // 从键盘读取
fputc(ch, stdout); // 输出到屏幕
八、补充知识点
文件路径说明
-
绝对路径:从根目录开始的完整路径
-
相对路径:
-
.表示当前目录 -
..表示上级目录
-
注意事项:路径中尽量避免使用中文
文件打开失败处理
-
返回
NULL指针表示打开失败 -
使用
perror函数输出具体错误信息 -
及时检查返回值,避免后续操作出错
文件指针管理
-
fclose不会自动将指针置为NULL -
关闭后手动置空,防止野指针
-
良好的编程习惯:关闭即置空
(敬请期待……)
