1、含义:
存储在外存储器上,相较于常量、变量、数据等都是存储在内存储器上的。
键盘是输入文件stdin;
显示器是输出文件stdout;
写文件,我们理解为输出,从内存到外存;比如printf,fprintf,fputc,fputs,fwrite;
读文件,我们理解为输入,从外存到内存;比如scanf,fscanf,fgetc,fgets,fread;
2、分类:
1)按照存取方式:
顺序存取:读写操作总是从文件的开始位置开始;
随机存取:读写操作可以从文件的任意位置进行。
2)按照存取形式:
文本文件:每个字符都是以ASCII码值的形式存储;定长译码编码,但文件可识别。
二进制文件:把数据按其在内存中的存储形式(二进制码)形式存储;不定长译码编码,但文件不可识别。
例如:
3.14,文本文件,会将每个数字看做是字符存储的,一个字符占一个字节;//打开文件后,所见即所得;
若作为二进制文件存储的话,如果使用float类型,则是占4个字节,使用double则是占8个字节。//打开文件后,是乱码;
但如果文本文件和二进制文件都存储的是字符数组的内容的话,打开二进制文件,看到的是对应的十六进制数。
3、文件指针
#include <stdio.h>
typedef struct{
short level; //缓冲区满或空 程度
unsigned flags;//文件状态标志
char fd; //文件描述符
unsigned char hold;// 如无缓冲区不读取字符
char filename[20];//文件名
char path[30];//文件路径
}FILE;
FILE* fp;
4、打开文件
对文件进行读写操作前,需要打开文件:
FILE* fp = fopen(文件名,文件的打开方式);
例如:
FILE* fp = fopen("test.txt","r");
FILE* fp = fopen("\\nand_flash\\test.txt","r");\\用两个/表示一个\
若文件无法打开,会返回NULL。
故:
FILE* fp;
if((fp = fopen("test.txt","r"))==NULL)
{
printf("fopen file fail\n");
exit;
}
打开方式 | 含义 | 打开方式 | 含义 |
“r” | 只读,打开文本文件,文件必须存在 | “r+” | 可读写,打开文本文件,文件必须存在 |
“w” | 只写,打开文本文件,文件不必存在,若存在,fopen的时候内容会被清除 | “w+” | 可读写,建立并打开新的文本文件,文件可以不存在,如果存在,fopen的时候内容会被清除 |
“a” | 追加写,文件可以不存在,从文本文件尾开始添加 | “a+” | 可读写,打开文本文件,文件可以不存在,在文件末尾添加 |
"rb" | 只读,打开二进制文件,文件必须存在 | "rb+" | 读写,打开二进制文件,文件必须存在 |
“wb” | 只写,打开二进制文件,文件不必存在,若存在,内容会被清除 | “wb+” | 读写,建立并打开新的二进制文件,文件可以不存在,如果存在,内容会被清除 |
"ab" | 追加,文件可以不存在,从二进制文件尾开始添加 | "ab+" | 读写,打开二进制文件,文件可以不存在,在文件末尾添加 |
r与r+比较:二者都需要先建立文件;r+增加了可写的功能,即:打开一次文件,可以写文件,读文件;写的时候是在文件位置指针的位置写的,会覆盖指针后面的内容。写几个字节覆盖几个字节。
r+的写优势:1)不会清除原文件的所有内容,通过fseek()函数来改变文件位置指针来写内容(写几个,覆盖几个)。2)读写文件时,只需要打开一次文件即可。
w与w+比较:二者对文件的存在都没有要求,如果文件存在,fopen的时候,原文件被删除,重新创立了新的文件;w+增加了读功能,即:写入文件后,通过fseek来更改文件位置指针,还可以将文件的内容读出来,
注意,w+是无法先读后写,因为,使用fopen后,就是一个空的文件。
r与w的比较:r文件必须要存在;w文件可存在,可不存在,如果存在,原文件中的内容会被覆盖(fopen的时候,原文件被删除,重新生成了一个同名的文件),如果不存在,会建立这个文件。
w的优势,重新生成一个新的文件,并且会覆盖原文件。
r+与w+的比较:二者都既能读又能写;r+要求文件存在,w+不要求文件存在,若存在,则会删除重新创建新的文件(即使用w+属性,无论文件存不存在,都会重新创建);
r+可以先写后读,也可以先读后写(因为文件已存在,且其中有内容),w+只能先写后读,因为fopen之后,文件为新建的文件为空,故只能先写后读。
w与a的比较:二者都不要求文件是否存在;w无论文件存在与否,都会删除文件,新建文件;a的话,如果文件未创建的话,与w一样,如果文件创建的话,则会在文件末尾续写内容。
a与a+的比较:二者都不要求文件是否存在,都不能改变文件的原内容;a只能在末尾添加,文件位置指针无效(即fseek无效);a+只能在结尾追加写, 文件位置指针只对读有效 (写操作会将文件指针移动到文件尾)
5、关闭文件
对文件读写完成后,应该关闭,防止丢失数据;
关闭文件的实质,是释放文件指针,使文件指针变量不再指向该文件。
fclose(fp);
//关闭成功返回0;
//关闭失败返回非0
6、文件的读写
6.1 fscanf 和fprintf //读写文本文件,数据格式任意
记忆:fscanf与fprintf 与scanf 和printf的格式及含义基本上是相同的;
scanf,是从键盘(stdin文件)读取一个值,并赋值给一个变量;//fscanf也是从文件中读取值,赋给某个变量
scanf("%d",&m)等价于 fscanf(stdin,"%d",&m);
printf,是将一个变量的值,写入到显示器(stdout文件);//fprintf也是将某个变量写到文件中;
printf("%d",n);等价于 fprintf(stdout,"%d",n);
1)fprintf(文件指针,格式字符串,输出项表)
例如:
fprintf(fp,"%d",m);//将变量m以%d的形式写到fp指向的文件中
2)fscanf(文件指针,格式字符串,输入项表)
例如:
fscanf(fp,"%d",&n);//注意取地址符号&//将fp所指的文件以%d的形式读取到变量n中
6.2 fputc(putc)和fgetc(getc)//从文本文件中读写字符
fputc(ch,fp);//ch可以是字符常量,可以是字符变量,写入到fp所指的文件中
putchar(ch);等价于fputc(ch,stdout);
ch = fgetc(fp);//从fp所指的文件中读取字符作为返回值赋给字符型变量ch
ch = getchar();等价于ch = getc(stdin);
6.3 fputs和fgets函数// 从文本文件中读写字符串
fputs(str,fp);//str是待写入文件的字符串的首地址
//注意:字符串最后的\0不会写入文件,也不会自动加'\n';
写入成功,函数值为非0,否则为0;
fgets(str,n,fp);//str是存放字符串的起始地址;n是int型变量
//从fp所指的文件中读n-1个字符依次放入到以str为旗帜地址的内存中,读入结束后,自动在最后加'\n',并以str作为函数值返回。
//注意:调用该函数时,最多只能读取n-1个字符。要为'\0'保留一个字符的空间
6.4 fwrite和fread//二进制文件中读写数据
fwrite(buffer,size,count,fp);
//buffer为指针,代表内存中一段存储空间的首地址;
size,代表每单元的字节数;
count代表要进行读写的单元数
//将以buffer为其实地址的内存中的count个单元,每个单元size个字节写到fp所指的文件中。
int a[4]={1,2,3,4}; fwrite(a,2,4,fp);
//将以a为起始地址的内存中的4个单元,每单元2个字节写(输出)到fp所指的文件中。
fread(buffer,size,count,fp);
//buffer是指针,代表内存中存储空间的地址;
count代表进行读写的单元数;
size带包每单元的字节数;
//从fp所指的文件中读(输入)count个单元,每个单元size个字节,到以buffer为起始地址的内存中。
int a[4];
fread(a,2,4,fp);
//从fp所指的we年中读4个单元,每个单元2个字节,到以a为起始地址的内存中。
7、判断文件是否结束
1)feof(fp); 判断文件是否结束------ f end of file//可以判断二进制文件,也可以判断文本文件
文件结束:返回值为1;
文件没有结束,返回值为0;
2)EOF;//文本文件
因为文本文件都是ASCII码,0-255,不可能为-1,所以使用EOF作为文本文件的结束标志。
8、文件定位函数
文件fopen后,文件位置指针指向文件的开头,第一个数据之前;//注意是文件位置指针,不是文件指针
文件fclose后,文件位置指针指向文件末尾,最后一个数据之后。
对数据进行读操作后,文件位置指针指向尚未读数据之前,即是从指针后的数据开始读。
当数据进行写操作后,文件位置真值指向刚写入数据之后。
我们使用fseek函数实现改变文件的位置指针。
起始点 | 名称 | 代表数字 |
文件开始位置 | SEEK_SET | 0 |
文件当前位置 | SEEK_CUR | 1 |
文件末尾位置 | SEEK_END | 2 |
fseek(fp,offset,origin);//一般用于二进制文件
offset是以origin为基点,以字节为单位的位移量,当offset为正整数,表示位置指针从指定位置向后移动,当offset为负整数,表示位置指针从指定位置向前移动,为长整型。
fseek(fp,30L,SEEK_SET);//位置指针从开始位置向后移30个字节。
fseek(fp,-10*sizeof(int),SEEK_END);//位置指针从文件尾部位置向前移10*sizeof(int)个字节。
fseek(fp,0L,SEEK_SET);//位置指针移动到开始位置。
fseek(fp,0L,SEEK_END);//位置指针移动到末尾位置。
long t = ftell(fp);
//返回当前位置指针据文件开头的字节数
//该函数可以用来获取文件的大小
fseek(fp,0L,SEEK_END);
long t = ftell(fp);
rewind(fp);//无返回值
//使文件位置指针返回到文件开头位置,等价于 fseek(fp,0L,SEEK_SET);
9、总结
1)c语言中关于文件的操作都是以f开头的。
2)r+,w+,a+,其实都可以通过r,w,a及fseek函数多次操作实现。