什么是文件
1.文件是指硬盘上的文件
2.类别:程序文件,数据文件。
3.程序文件(在windows环境下·):源文件(后最为.c),目标文件(后缀为.obj),可执行文件(后缀为.exe).
4. 数据文件:存储的是程序运行时读写的数据,可以是读取或输出的文件。
文件名
1.组成部分:文件路径+文件名主干+文件后缀。
2.windows系统下:文件名:D:\Work\Report\2025_Q2_Sales.xlsx。
1.文件路径:D:\Work\Report\
2.文件名主干:2025_Q2_Sales
3.文件后缀:xlsx
3.linux与macOS系统下:/home/user/Documents/Project_Plan.pdf
1.文件路径:/home/user/Documents/
2.文件名主干:Project_Plan
3.文件后缀:pdf
4.无路径(在当前目录下的文件): 文件名主干+文件后缀。
5.特殊情况:无后缀,多后缀。
文件类型
1.类型:文本文件,二进制文件。
2.文本文件:以ASCII字符形式存储的文件。
3.二进制文件:以二进制形式存储的文件。
4.注意点:字符用ASCII,数值两个都能用。
5.测试(要在编译器里找,二进制编辑器):
#include <stdio.h>
int main()
{
int a = 10000;
FILE* pf = fopen("test.txt", "wb");
if (pf == NULL) {
printf("文件打开失败!\n");
return 1;
}
fwrite(&a, 4, 1, pf);
fclose(pf);
pf = NULL;
return 0;
}
文件缓冲区
作用:就是相当于中转站的意思。数据有两个地点:内存,硬盘。对于数据文件采用的是缓冲文件系统。会为程序中每一个正在使用的文件开辟一块“文件缓冲区”。
文件指针
1.解释:每个被使用的文件在内存里开辟一个文件信息区,这个信息区存储着关于文件信息,是以一个结构体的形式其变量储存这信息,结构体的名称:FILE。
2.定义:
FILE* pf;
3.特殊:不同的编译器,有这不同的FILE 结构体(里面的变量会有所不同)。
4.作用:通过文件指针变量我们能找到相应文件。
文件的打开和关闭
1.要用函数:(打开)fopen(关闭) fclose。
2.fopen 原型:
FILE * fopen ( const char * filename, const char * mode );
3.fclose 原型:
int fclose ( FILE * stream );
4.打开方式
文件使用方式 | 含义 | 如果指定文件不存在 |
“r”(只读) | 为了输入数据,打开一个已经存在的文本文件 | 出错 |
“w”(只写) | 为了输出数据,打开一个文本文件 | 建立一个新的文件 |
“a”(追加) | 向文本文件尾添加数据 | 出错 |
“rb”(只读) | 为了输入数据,打开一个二进制文件 | 出错 |
“wb”(只写) | 为了输出数据,打开一个二进制文件 | 建立一个新的文件 |
“ab”(追加) | 向一个二进制文件尾添加数据 | 出错 |
“r+”(读写) | 为了读和写,打开一个文本文件 | 出错 |
“w+”(读写) | 为了读和写,建立一个新的文件 | 建立一个新的文件 |
“a+”(读写) | 打开一个文件,在文件尾进行读写 | 建立一个新的文件 |
“rb+”(读写) | 为了读和写打开一个二进制文件 | 出错 |
“wb+”(读写) | 为了读和写,新建一个新的二进制文件 | 建立一个新的文件 |
“ab+”(读写) | 打开一个二进制文件,在文件尾进行读和写 | 建立一个新的文件 |
5.口诀:文件操作看模式,文本二进制带b(rb、wb...)。 r读w写a追加,存在要求各不同。 r/rb/r+/rb+,文件不在就报错。 a/ab想追加,无文件也会出错。 w/wb/w+/wb+,没有就建新文件。 a+/ab+读写追,缺文件时新创建 。读写特性要分清,操作前先想场景, 记清口诀用得灵!
文件的顺序读写
1.函数:
功能 | 函数名 | 适用于 |
---|---|---|
字符输入函数 | fgetc | 所有输入流 |
字符输出函数 | fputc | 所有输出流 |
文本行输入函数 | fgets | 所有输入流 |
文本行输出函数 | fputs | 所有输出流 |
格式化输入函数 | fscanf | 所有输入流 |
格式化输出函数 | fprintf | 所有输出流 |
二进制输入 | fread | 文件 |
二进制输出 | fwrite | 文件 |
2.输出(入)流:输入流是 “外部→程序” 的数据读取通道,输出流是 “程序→外部” 的数据写入通道,本质是数据流向的区分。简单说:“输入流是程序‘读’外部数据,输出流是程序‘写’数据到外部”
文件的随机读写
1.函数:fseek ftell rewind
fseek
1.原型:
int fseek(FILE *stream, long offset, int origin);
2.功能:移动文件内部指针到指定位置。
3.函数分析:
stream:文件指针(如 fopen返回的FILE*),标识操作的文件。
offset:偏移量(long 类型),可正(向后移)、可负(向前移),表示相对于 origin 要移动的字节数。
origin:起始位置,是以下宏之一:SEEK_SET:从文件开头(0偏移处)开始算。SEEK_CUR:从当前文件指针位置开始算。SEEK_END:从文件末尾开始算(结合负offset 可访问文件末尾前内容)。
ftell
1.原型:
long ftell(FILE *stream);
2.功能:获取当前文件内部指针的位置 (相对于文件开头的字节偏移量)
3.函数分析:返回当前文件指针位置(long类型);失败返回 -1L
(如文件异常)
rewind
1原型:
void rewind(FILE *stream);
2.功能:简化版的 fseek,直接将文件内部指针重置到文件开头(等价于 fseek(stream, 0, SEEK_SET)
)。
3.函数分析:无返回值,调用更简洁;常用于 “读完文件后重新从头开始读” 的场景
文件的结束判定
在 C 语言文件操作中,“文件结束判定” 是极易踩坑的关键环节。不少开发者误用 feof
函数,导致程序逻辑异常。本文结合代码示例,详细拆解文本文件、二进制文件的结束判定规则,帮你精准把控文件读写流程
一、被 “误解” 的 feof
:别把它当 “预判工具”
(一)核心误区:feof
不是 “预判文件是否结束”
feof
的作用是 “检测文件结束标志是否被设置”,而非 “预判文件即将结束” 。只有当程序实际尝试读取文件末尾并失败后,feof
才会返回真。直接用 !feof(fp)
做循环条件,会导致最后一次读取操作的结果被重复处理(因为文件结束标志的触发滞后于实际读取动作 )。
(二)feof
的正确用法:“事后判定” 结束原因
feof
应在 读取操作执行后,用来区分 “正常文件结束” 和 “读取错误导致的意外结束” ,
二、文本文件:用 EOF
/NULL
实时判定
文本文件读写依赖 fgetc
(读字符)、fgets
(读行)等函数,它们的返回值直接体现 “是否到文件结束” 。
(一)fgetc
+ EOF
判定
fgetc
读取失败(或到文件末尾)时返回 EOF
(本质是 -1
,但需用 int
类型接收,避免 char
类型截断问题 )
(二)fgets
+ NULL
判定
fgets
读取到文件末尾或失败时返回 NULL
,适合按行读取文本
三、二进制文件:用 fread
/fwrite
返回值判定
二进制文件(如 .bin
、自定义格式文件 )读写依赖 fread
/fwrite
,它们的返回值是 “实际成功读写的数据块数量” ,以此判断是否到文件结束。
(一)fread
判定逻辑fread(ptr, size, count, fp)
尝试读取 count
个大小为 size
的数据块,返回 实际成功读取的块数量 。若返回值 < count
,说明读取异常(可能到文件末尾或发生错误 )
(二)关键区别:文本 vs 二进制判定
文件类型 |
读取函数 |
结束判定依据 |
核心逻辑 |
---|---|---|---|
文本文件 |
|
返回值是否为 |
|
|
返回值是否为 |
| |
二进制文件 |
|
返回的 “数据块数量” 是否达标 |
while( fread(...) == 预期块数量 ) |