一、为什么要使用文件
我们每次写的程序都是存储在内存中的,程序结束内存就会回收,数据就会丢失,如果想长久的保存数据,就要用到文件
二、文件的概念
1、程序文件
包括 源文件 .c 目标文件 .obj 可执行程序 .exe
2、数据文件
文件的内容是程序运行时读写的数据
3、文件名
文件路径 文件名主干 文件后缀
三、二进制文件和文本文件
数据在内存中以二进制形式存储,如果不转换直接输出到外存的文件中,就是二进制文件 如果转化成ASCII字符形式存储的文件就是文本文件 字符数据在文件中一律以ASCII码值存储,数值型数据既可以用ASCII形式存储,也可以二进制存储
四、文件的打开和关闭
1、流
流是一种抽象的概念,是一条双向流向输入输出也就是系统和文本的河流,我们输入输出数据都要打开流后操作
标准流
在C语言程序启动时,默认打开了3个流 ①stdin-标准输入流,像使用scanf函数从键盘输入就是标准输入流的一种 ②stdout-标准输出流,像使用printf函数将信息输出到桌面上就是标准输出流的一种 ③stderr-标准错误流,大多数环境中输出到显示器界面 它们三个流的类型是 FILE * ,通常称为文件指针,我们通过它来维护各种流的操作
2、文件指针
每个被使用的文件都在内存中开辟了一个相应的文件信息区,用来存放文件信息,保存在一个结构体变量中,它的结构体类型由系统声明,取名FILE 这是在vs2013编译环境提供的stdio.h头文件下的文件类型声明:
代码语言:javascript复制struct _iobuf {
char *_ptr;
int _cnt;
char *_base;
int _flag;
int _file;
int _charbuf;
int _bufsiz;
char *_tmpfname;
};
typedef struct _iobuf FILE;
不同编译器的FILE类型包含的内容大同小异,每当打开一个文件的时候,系统会根据文件的情况自动创建一个FILE变量,并填充信息 创建文件指针变量:
代码语言:javascript复制FILE* pf;
定义pf是一个指向FILE类型数据的指针变量,使pf指向某个文件的文件信息区(文件信息区是一个结构体变量),通过其中的信息就能访问该文件 通过文件指针能够间接找到与它关联的文件
3、文件的打开和关闭
文件在使用时打开,使用结束后关闭 我们用fopen打开文件,fclose关闭文件
代码语言:javascript复制//打开⽂件
FILE * fopen ( const char * filename, const char * mode );
//关闭⽂件
int fclose ( FILE * stream );
filename就是文件名,mode就是打开方式,下边是常用的打开方式: 每四行为一个家族,分别是r家族、w家族、a家族,不同家族家族成员的区别差不多
文件使用方式 | 含义 | 如果指定文件不存在 |
---|---|---|
“r”只读 | 输入数据,打开一个已经存在的文本 | error |
“rb”只读 | 输入数据,打开一个二进制文件 | error |
“r ”读写 | 读和写数据,打开一个文本 | error |
“rb ” | 读和写数据,打开一个二进制文件 | error |
“w”只写 | 输出数据,打开一个文本 | 创建一个新的文件 |
“wb”只写 | 输出数据,打开一个二进制文件 | 创建一个新的文件 |
“w ”读写 | 读和写数据,新建一个文件 | 创建一个新的文件 |
wb | 读和写数据,新建一个二进制文件 | 创建一个新的文件 |
“a”追加 | 向文本尾部添加数据 | 建立一个新的文件 |
“ab”追加 | 向二进制文件尾部添加数据 | 创建一个新的文件 |
“a ” | 打开一个文件,在文件尾读写 | 创建一个新的文件 |
“ab ” | 打开一个二进制文件,在文件尾读写 | 创建一个新的文件 |
五、文件的顺序读写
1、顺序读写函数
函数名 | 功能 | 适用于 |
---|---|---|
fgetc | 字符输入 | 所有输入流 |
fputc | 字符输出 | 所有输出流 |
fgets | 文本行输入 | 所有输入流 |
fputs | 文本行输出 | 所有输出流 |
fscanf | 格式化输入 | 所有输入流 |
fprintf | 格式化输出 | 所有输出流 |
fread | 二进制输入 | 文件输入流 |
fwrite | 二进制输出 | 文件输出流 |
六、文件的随机读写
1、fseek
根据文件指针的位置和偏移量来定位文件指针 如果成功,返回非零值;如果失败,返回零
代码语言:javascript复制int fseek ( FILE * stream, long int offset, int origin );
第一个参数是文件指针 第二个参数是相对于第三个参数origin的偏移量 第三个参数是开始时的位置,一般为下面常量之一
常量 | 描述 |
---|---|
SEEK_SET | 文件的开头 |
SEEK_CUR | 文件指针的当前位置 |
SEEK_END | 文件的末尾 |
这里我们拿cplusplus网站上的一个例子举例:
代码语言:javascript复制#include <stdio.h>
int main ()
{
FILE * pFile;
pFile = fopen ( "example.txt" , "wb" );
fputs ( "This is an apple." , pFile );
fseek ( pFile , 9 , SEEK_SET );
fputs ( " sam" , pFile );
fclose ( pFile );
return 0;
}
分析: 定义一个文件指针pFile,以二进制写入的方式创建example.txt文件,pFile指向这个文件,写入This is an apple.到这个文件中,然后从头开始找到第九个位置也就是an中的n,光标移到这个位置,然后输入 sam,会将原本在这的数据覆盖,n ap就变成了 sam,最终就是This is a sample.
2、ftell
代码语言:javascript复制long int ftell ( FILE * stream );
返回指针相对于起始位置的偏移量
3、rewind
代码语言:javascript复制void rewind ( FILE * stream );
让文件指针的位置回到起始位置
七、文件读取结束的判定
1、feof
这里我们介绍一个函数:feof 它的作用是当文件读取结束的时候,判断读取结束的原因是否是遇到文件尾结束,但它的返回值不能够直接判断文件是否结束
2、fgetc
判断返回值是否为EOF
3、fgets
判断返回值是否为NULL
4、二进制文件的读取结束判断
判断返回值是否小于实际要读的个数
八、文件缓冲区
ANSIC 标准采用“缓冲⽂件系统” 处理数据⽂件,缓冲文件系统是系统自动地在内存中为程序中每⼀个正在使用的文件开辟⼀块“文件缓冲区”,从内存向磁盘输出数据会先送到内存中的缓冲区,装满缓冲区后才一起送到磁盘上,如果从磁盘向计算机读入数据,则从磁盘⽂件中读取数据输入到内存缓冲区(充满缓冲区),然后再从缓冲区逐个地将数据送到程序数据区(程序变量等),缓冲区大小由C编译系统决定
今天就分享到这里了