一.为什么使用文件
之前我们写的程序的数据都是存储到内存里面的,当程序结束时,内存回收,数据丢失,
再次运行程序时,就看不到上次程序的数据,如果要程序的数据一直保存得使用文件
二.文件
文件一般可以分为俩种:
1.程序文件
包括源程序文件(后缀为 .c)、目标文件(Windows环境下后缀为 .obj)、可执行程序(Windows环境下后缀为 .exe)
2.数据文件
文件的内容不一定是程序文件,而是程序运行时读写的文件,比如程序运行时需要从中读取数据的文件或输出的文件,举例如下:
三.数据在文件中是怎么存储的?
数据在内存是以二进制形式存储,而在文件中:
字符一律按ASCLL码值形式存储
数值型数据既可以以ASCLL码值形式存储,也可以以二进制形式存储
举例:
如10000,以ASCLL码值形式存储到磁盘,在磁盘上占5个字节(一个字符一个字节),以二进制形式存储,占4个字节,图像如下:
四.二进制文件和文本文件
数据在内存是以二进制形式存储,如果不加以转化就输出到外存的文件,就是二进制文件,
以ASCLL码值形式存储的文件为文本文件
五.流和标准流
1.流
程序的数据要输出到各种设备,也需要从外部设备获取数据,由于设备的不同导致输入输出操作不同,为了方便就有了流的概念,c程序对文件、键盘等进行输入输出操作都是通过流操作的
一般情况下,向流中输入输出数据都是先打开流,在进行操作
2.标准流
之前的scanf函数从键盘输入信息、primtf函数向屏幕输出信息等却没看见打开流,是因为c程序在启动的时候默认打开了三个流:
stdin ---标准输入流,大多数环境下从键盘上输入,scanf就是从标准输入流中读取数据的
stdout ---标准输出流,大多数环境下从屏幕上输出,printf就是将信息输出到标准输出流中
stderr ---标准错误流,大多数环境下从屏幕上输出
六.文件指针
每打开一个文件,系统就会根据文件情况自动创建FILE结构体变量,并填充其中的信息,一般都是通过一个FILE的指针来维护其结构变量,即文件指针,该指针可以找到与它关联的文件
七.文件的打开和关闭
文件在读写前应该打开文件,使用结束后关闭文件,不然会造成内存泄漏,数据丢失等
ANSIC规定使用fopen打开文件,fclose关闭文件
1.fopen
形式:
功能:
打开fileaname指定的文件,同时将文件和一个流进行关联,后续对流的操作是通过函数返回的指针进行维护的(如fputc、fputs等),具体对流(关联的文件)的操作是通过参数mode来指定的
参数:
filename:表示打开文件的名字,可以是相对路径,也可以是绝对路径
mode:表示打开文件的操作方式
返回值:
打开文件成功返回一个指向FILE结构体的指针,通过操作流(统一接口)指向文件信息区,关联到此文件
失败时返回NULL,所以每次打开文件都要检查是否打开成功
文件打开方式(mode参数)
模式 | 描述 | 文件存在 | 文件不存在 |
“ r ” | 只读 | 正常打开文件 | 返回NULLL |
“ w ” | 只写(覆盖) | 清空文件类容 | 创建新文件 |
" a " | 追加写入(从末尾) | 从末尾写入 | 创建新文件 |
" r+ " | 读写(从开头) | 正常打开文件 | 返回NULL |
" w+ " | 读写(覆盖) | 清空文件类容 | 创建新文件 |
" a+ " | 读写(追加) | 从末尾写入 | 创建新文件 |
"rb""wb"等 | 二进制模式(加b) | 同上 | 同上 |
2.fclose
形式:
功能:
关闭参数steam关联的文件,并取消其关联关系。与该流关联的内部缓冲区解除关联并刷新(将为写入磁盘的输入缓冲区的类容写入,将未读取的输出缓冲区的类容丢弃)所以文件指针会变为野指针,得及时置为NULL
参数:
steam:指向要关闭文件流的FILE结构体的指针
返回值:
关闭成功返回0,否则返回EOF
应用举例:
. ----表示当前路径
.. ----表示上一级路径
/ ----表示分割目录层级
相对文件举例:data.txt(表示当前路径的data.txt)或(./../data.txt)
绝对路径举例:C:\Users\xxx\Desktop
八.文件的顺序读写
函数名 | 功能 | 适用于 |
fgetc | 从输入流读取一个字符 | 所有输入流 |
fputc | 向输出流写入一个字符 | 所有输出流 |
fgets | 从输入流读取一个字符串 | 所有输入流 |
fputs | 向输出流写入一个字符串 | 所有输出流 |
fscanf | 从输入流读取带有格式的数据 | 所有输入流 |
fprintf | 向输出流写入带有格式的数据 | 所有输出流 |
fread | 从输入流读取一块数据 | 文件输入流 |
fwrite | 向输出流写入一块数据 | 文件输出流 |
1.fputc
形式:
功能:
将参数character指定的字符写入到stream指定的输出流里,字符会被写入内部指示器当前指向的位置(如有字符将被覆盖),写入后指示器向前移动一个位置
参数:
character:被写入的字符
steam:指针,指向了输出流
返回值:
写入成功返回写入的字符(int形式的)
失败时返回EOF(通常为-1)
应用:
2.fgetc
形式:
功能:
从参数stream指定的输入流读取字符,读取当前指示器指向的字符后,指示器也会向前移动一个位置
参数:指针,指向了输入流
返回值:
读取成功时返回读取的字符(int类型的)
读取失败或读取到文件末尾时返回EOF
应用:
2.feof和ferror
feof
形式:
功能:
检测stream指针指向的流是否遇到了文件末尾。如果在读取文件到末尾的时候,读取就会停止,这时读取函数就会在对应的流上设置一个文件结束的指示符,这个指示符会被 feof() 检测到,如果检测到指示符就返回非0的值,否则返回0
ferror
形式:
功能:
检测stream指针指向的流是否读/写错误。如果读/写错误,文件读写就会停止,读写函数就会在对应的流上设置一个错误指示符,这个指示符会被ferror检测到,被检测到指示符被设置就会返回非0的值,否则返回0.
应用:
3.fputs
形式:
功能:
将str指向的字符串写入到stream指向的输出流里(不包括文件的控制符\0)
参数:
str:指针,指向要写入的字符串(必须以\0结尾)
stream:指针,指向输出流
返回值:
成功时返回非负数
失败时返回EOF
应用:
4.fgets
形式:
功能:
从stream指定的输入流读取字符串,直至读到换行符、文件末尾、指定字符数(包括结尾\0),然后将读取的字符串存储到str指向的空间里
参数:
str:指向字符数组的指针,用来存储读取的字符
num:最大读取字符数(实际最多读取num-1个,每次读取都会在结尾加\0)
stream:指针,指向输入流
返回值:
成功时返回str
读取到文件末尾或读取错误时返回NULL
应用:
5.fprinrf
形式:
功能:
将格式化数据输出到stream指定的流里
参数:
stream:指针,指向要写入的文件流里
format:格式化字符串(%d、%f等)
.... :提供与格式化字符串中说明符
返回值:
成功时返回写入字符个数
失败时返回负值
应用:

6.fscanf
形式:
功能:
从stream指定的文件流中读取格式化数据的函数
参数:
stream:指针,指向输入流
.... :可变参数列表,提供存储数据的地址
其他和scanf一样
返回值:
成功时返回成功填充到可变参数列表的项数,但可能少于预期,有如下原因:
格式化字符与数据不匹配
读取发生错误
在读取成功前读到文件末尾或读取错误返回EOF
应用:
7.fwrite
形式:
功能:
将ptr指向的数据块(可控制)写入到stream指向的输出流里(以二进制写入,所以得在使用前已二进制可写方式打开)
参数:
ptr:指针,指向要写入的数据块
size:要写入每个数据块的大小(单位字节)
num:要写入数据项的数量
stream:指针,指向了要写入的文件输出流
返回值:
返回写入的项数
应用:
8.fread
形式:
功能:
从stream指定的文件输入流中读取数据块(读取二进制形式文件)
参数:
ptr:指针,指向存储读取的数据的空间
size:要读取每个数据块的大小
count:读取数据块的总量
stream:指针,指向要读取数据的文件流
返回值:
读取的项数
应用:

9.sprintf
形式:
功能:
将格式化数据转化为一个字符串
参数:
str:指针,指向存储生成的字符串
返回值:
成功时返回存储的字符数(不包括\0)
失败时返回负值
应用:
10.sscanf
形式:
功能:
从字符串读取格式化数据
参数:
s:指针,指向要读取的字符串
返回值:
成功时返回解析成功并赋值的项数
失败时返回EOF
应用:
九.文件的随机读取
1.fseek
形式:
功能:
调整文件指示器的位置,可以从想读/写的位置读/写
参数:
stream:指针,指向一个流(如文件流)
origin:文件指示器的初始位置,可设置,有以下可能取值:
‘
offset:相对于origin的偏移量
应用:
2.ftell
形式:
功能:
返回文件指示器相对于起始位置的偏移量
应用:
3.rewind
形式:
功能:
是文件指针回到起始位置
十.文件缓冲区
系统会自动在内存中为程序中每一个正在使用的文件开辟一块“文件缓冲区”。从内存向磁盘输出数据先会送到文件缓冲区,装满后才一起送到磁盘上.
所以在读写模式下,写完后再读,可能数据还没输出到文件,导致读不到数据,以下有个函数可以刷新文件缓冲区,能及时读到数据,
fflush
形式:
功能:
强制刷新stream指定流的缓冲区,但对输入流未定义
参数为NULL时刷新所有打开的输出流
返回值:
成功时返回0,失败时返回EOF
证明代码:
#include <stdio.h>
#include <windows.h>
//VS2022 WIN11环境测试
int main()
{
FILE* pf = fopen("dtat.txt", "w");
fputs("abcdef", pf);//先将代码放在输出缓冲区
printf("睡眠10秒-已经写数据了,打开dtat.txt文件,发现文件没有内容\n");
Sleep(10000);
printf("刷新缓冲区\n");
fflush(pf);//刷新缓冲区时,才将输出缓冲区的数据写到⽂件(磁盘)
//注:fflush 在⾼版本的VS上不能使⽤了
printf("再睡眠10秒-此时,再次打开dtat.txt文件,文件有内容了\n");
Sleep(10000);
fclose(pf);
//注:fclose在关闭⽂件的时候,也会刷新缓冲区
pf = NULL;
return 0;
}