C语言有关文件操作的函数主要有下面这些:
- fopen:打开一个文件
- fclose:关闭一个文件
- fgetc:从文件中读取一个字符
- fputc:向文件中写入一个字符
- fgets:从文件中读取一个字符串
- fputs:向文件中写入一个字符串
- fprintf:向文件中格式化写入数据
- fscanf:从文件中格式化读取数据
- fread:以二进制形式从文件中读取数据
- fwrite:以二进制形式向文件中写入数据
- getw:以二进制形式从文件中读取一个整数
- putw:以二进制形式向文件中写入一个整数
- feof:文件结束
- ferror:文件读写错误
- clearerr:清除文件错误日志
- ftell:了解文件指针当前位置
- rewind:反绕
- fseek:随机定位
下面详细讲解一下各个函数的用法:
1、fopen、fclose
fopen
函数原型:FILE * fopen(const char * path, const char * mode)
参数path字符串包含将要打开的文件路径及文件名,参数mode字符串则代表着流形态。
文件顺利打开后,指向该流的文件指针就会被返回。如果文件打开失败则返回NULL,并把错误代码放在error中。
mode有下列几种形态字符串:
上述的形态字符串都可以再加一个 b 字符,如 rb、w+b 或 ab+ 等组合,加入 b 字符用来告诉函数库以二进制模式打开文件。如果不加 b,表示默认加了 t,即 rt、wt,其中 t 表示以文本模式打开文件。
fclose
函数原型:int fclose( FILE *fp )
如果流成功关闭,fclose 返回 0,否则返回EOF(-1)
可以在fclose(fp)后使用
if(fclose())
{
perror("fclose");
}
来判断是否成功关闭文件,关闭失败,则fclose返回1并输出错误原因
函数应用实例:
#include<stdio.h>
int main()
{
FILE *fp = NULL;
fp = fopen("text.txt","r");
if(fp == NULL)
return -1;
fclose();
fp = NULL;//需要指向空,否则会指向原打开文件地址
return 0;
}
2、fgetc、fputc
fgetc
函数原型:int fgetc(FILE *fp)
从文件指针fp指向的文件中读取一个字符,读取一个字节后,光标位置后移一个字节。这个函数的返回值,是返回所读取的一个字节。如果读到文件末尾或者读取出错时返回EOF。
注意到虽然是返回一个字节,但是返回值类型为int而不知unsigned char,因为EOF为-1,返回值要能够表示-1。
fputc
函数原型:int fputc (int c, FILE *fp)
c是一个整型变量,是内存要写到文件中的字符(C语言中整型量和字符量可以通用)
在正常调用情况下,函数返回写入文件的字符的ASC||码值,出错时,返回EOF。当正确写入一个字符或一个字节的数据后,文件内部写指针会自动后移一个字节的位置。
函数应用实例:将一个文件中的大写字母转为小写字母,小写字母转为大写字母后保存到另一个文件中
#include<stdio.h>
int main()
{
char ch;
FILE *fp1,*fp2;
fp1 = fopen("a.txt","r");
if(fp1 == NULL)
return -1;
fp2 = fopen("b.txt","w");
if(fp2 == NULL)
return -1;
ch = fgetc(fp1);
while(ch != EOF)
{
if(ch >= 'a' && ch <= 'z')
ch -= 32;
else if(ch >= 'A' && ch <= 'Z')
ch += 32;
fputc(ch,fp2);
ch = fgetc(fp1);
}
fclose(fp1);
fp1 = NULL;
fclose(fp2);
fp2 = NULL;
return 0;
}
3、fgets、fputs
fgets
函数原型:char *fgets(char *str,int n,FILE *fp)
从由fp指出的文件中读取n-1个字符(因为第n个是'\0'),并把它们存放到由str指出的字符串数组中去,最后加上一个字符串结束符'\0'。如果文件中的该行不足n个字符,则读完该行就结束。若该行(包括最后一个换行符)的字符数超过n-1,则只返回一个不完整的行,但是,缓冲区总是以NULL字符结尾,对fgets的下一次调用会继续该行。函数成功将返回指向str的指针,失败或读到文件结尾返回NULL,因此不能直接通过fgets的返回值来判断函数是否是出错而终止的,应该借助feof函数或ferror函数来判断。
str:接收字符串的内存地址,可以是数组名,也可以是指针。
n:指出要读取字符串的个数。
fp:这是个文件指针,指出要读取的文件。
fputs
函数原型:int fputs(char *str,FILE *fp)
str是字符型指针,可以是字符串常量,或者存放字符串的数组首地址。
fp是文件指针。
向fp指向的文件写入一个字符串(不自动写入字符串结束标记符'\0')。成功写入一个字符串后,文件的位置指针会自动后移,函数返回值为非负整数,否则返回EOF。
函数应用实例:测试fgets
#include<stdio.h>
int main(int argc,char **argv)
{
FILE *fp1;
char str[256];
fp1 = fopen("a.txt","r");//a.txt中的内容是ABCabc123
if(fp1 == NULL)
return -1;
if(fgets(str,4,fp1) == NULL)//这里调用fgets一次,读取出3个字符
printf("失败");
else
printf("%s\n",str);
if(fgets(str,7,fp1) == NULL)//这里第二次调用fgets,读取出剩下的6个字符
{
printf("失败");
}
else
printf("%s\n",str);
if(fgets(str,2,fp1) == NULL)//由于文件已经读取完毕,因此返回NULL
printf("失败");
else
printf("%s",str);
return 0;
}
函数应用实例:将一个文件中的内容复制到另一个文件
#include<stdio.h>
int main(int argc,char **argv)
{
FILE *fp1,*fp2;
char str[256];
fp1 = fopen("a.txt","r");//a.txt中的内容是ABCabc123
fp2 = fopen("b.txt","w");//b.txt为空
if(fp1 == NULL)
return -1;
if(fp2 == NULL)
return -1;
if(fgets(str,4,fp1) == NULL)//这里调用fgets一次,读取出3个字符
printf("失败");
else
fputs(str,fp2);
if(fgets(str,7,fp1) == NULL)//这里第二次调用fgets,读取出剩下的6个字符
printf("失败");
else
fputs(str,fp2);
if(fgets(str,2,fp1) == NULL)//由于文件已经读取完毕,因此返回NULL
printf("失败");
else
fputs(str,fp2);
return 0;
}
4、fscanf、fprintf
fscanf
函数原型:int fscanf(FILE *fp,const char * format,[argument...])
fp:文件指针
format:格式化数据
根据数据格式(format)从输入流fp中写入数据,与fgets的差别在于:fscanf遇到空格和换行符时结束,注意空格时也结束,fgets遇到空格不结束。
(其实就是平时使用的scanf,只是需要指明操作的文件流罢了)
fprintf
函数原型:int fprintf(FILE *fp,const char *format,[argument]....)
根据指定的format发送信息由fp指定的文件,fprintf()只能和printf()一样工作,fprintf()的返回值是输出指定的字符串,发生错误时返回一个负值。
函数应用实例:格式化读取a.txt中的数据写入b.txt中
#include<stdio.h>
int main(int argc,char **argv)
{
FILE *fp1,*fp2;
int a,b,c,d;
fp1 = fopen("a.txt","r");
fp2 = fopen("b.txt","w");
if(fp1 == NULL)
return -1;
if(fp2 == NULL)
return -1;
while(!feof(fp1))
{
fscanf(fp1,"%d %d %d %d",&a,&b,&c,&d);
fprintf(fp2,"%d %d %d %d\n",a,b,c,d);
}
return 0;
}
5、fread、fwrite
fread
函数原型:size_t fread (void * buffer,size_t size,size_t count,FILE *fp)
size_t是标准C库中定义的,应为unsigned int,在64位系统中为long unsigned int
buffer:用于接收数据的内存地址
size:要读的每个数据项的字节数,单位是字节
count:要读count个数据项,每个数据项size个字节
fp:要进行操作的文件流
如果读取成功,则返回真实读取的项数,若大于count则意味着产生了错误。
fwrite
函数原型:
size_t fwrite(const void* buffer,size_t size,size_t,count,FILE *fp)
buffer:是一个指针,对fwrite来说,是要获取数据的地址
size:要写入内容的单字字节数
count:要进行写入size字节的数据项个数
fp:文件指针
如果写入成功则返回实际写入的数据块数目。
函数应用实例:将a中的9个字母复制到b中,每次复制3个字母
#include<stdio.h>
int main(int argc,char **argv)
{
FILE *fp1,*fp2;
int a[3];
fp1 = fopen("a.txt","rb");
fp2 = fopen("b.txt","wb");
if(fp1 == NULL)
{
printf("打开a失败");
return -1;
}
if(fp2 == NULL)
{
printf("打开b失败");
return -1;
}
if(fread(a,sizeof(char),3,fp1)!=0)
fwrite(a,sizeof(char),3,fp2);
if(fread(a,sizeof(char),3,fp1)!=0)
fwrite(a,sizeof(char),3,fp2);
if(fread(a,sizeof(char),3,fp1)!=0)
fwrite(a,sizeof(char),3,fp2);
if(fread(a,sizeof(char),3,fp1)!=0)
fwrite(a,sizeof(char),3,fp2);
return 0;
}
6、getw、putw
getw
函数原型:int getw(FILE *fp)
从fp所指向的文件读取下一个字(整数),返回读入的整数,如果文件结束或出错返回-1。
putw
函数原型:int putw(int w,FILE *fp)
将整数w写入fp指向的文件,返回输出的整数,如果出错,则返回EOF
这两个函数好像是以ASCII码值来读取和写入数据的,getw每次会读取4个ASCII码值的数据,如果一次读取的数据不足4个就会返回EOF(注意此时无法用putw写入剩下的数据),而且如果写入时w中不足4个数据,打开文件会发现后面不足的数据会追加上空格。这???是什么???博主也没有彻底搞懂这两个函数是怎么工作的,哪位大佬如果知道的话可以提醒一下我....
函数应用实例:将a中的数字复制到b中
#include<stdio.h>
int main(int argc,char **argv)
{
FILE *fp1,*fp2;
int n;
fp1 = fopen("a.txt","rb");
fp2 = fopen("b.txt","wb");
if(fp1 == NULL)
return -1;
if(fp2 == NULL)
return -1;
n = getw(fp1);
while(n != -1)
{
putw(n,fp2);
n = getw(fp1);
}
return 0;
}
7、feof
函数原型:int feof(FILE *fp)
如果文件结束,则返回非0值,否则返回0.
函数应用实例:
#include<stdio.h>
int main(int argc,char **argv)
{
FILE *fp;
int ch;
fp = fopen("a.txt","r");//a中的数据是123456
if(fp == NULL)
return -1;
for(int i=0;i<7;i++)
{
ch = fgetc(fp);
printf("%d\n",feof(fp));
}
return 0;
}
8、ferror
函数原型:int ferror(FILE *fp)
在调用各种输入输出函数(如putc,getc,fread,fwrite等)时,如果出现错误,除函数返回值有所反映外,还可以用ferror函数检查。 它的一般调用形式为 ferror(fp);如果ferror返回值为0(假),表示未出错。如果返回一个非零值,表示出错。(读到文件末尾不算出错)
函数应用实例:
#include<stdio.h>
int main(int argc,char **argv)
{
FILE *fp;
int ch;
fp = fopen("a.txt","r");//a中的数据是123456
if(fp == NULL)
return -1;
for(int i=0;i<7;i++)
{
ch = fgetc(fp);
printf("%d\n",ferror(fp));
}
return 0;
}
//输出结果:0000000
9、clearerr
函数原型:void clearerr(FILE *fp)
clearerr的作用是使文件错误标志和文件结束标志置为0,假设在调用一个输入输出函数时出现了错误,ferror函数值为一个非0值。在调用clearerr(fp)后,ferror(fp)的值变为0。
10、ftell
函数原型:long ftell(FILE *fp)
函数ftell用于得到文件位置指针当前位置相对于文件首的偏移字节数。在随机方式存取文件时,由于文件位置频繁的前后移动,程序不容易确定文件的当前位置。
因为ftell返回long类型,根据long型的取值范围-2^31~2^31-1,故对大于2.1G的文件进行操作时出错。
函数应用实例:
#include<stdio.h>
int main(int argc,char **argv)
{
FILE *fp;
int ch;
fp = fopen("a.txt","r");//a中的数据是123456
if(fp == NULL)
return -1;
for(int i=0;i<7;i++)
{
ch = fgetc(fp);
printf("%d\n",ftell(fp));
}
return 0;
}
//输出结果:1234566
11、fseek
函数原型:int fseek(FILE *fp,long offset,int fromwhere)
如果执行成功,fp将指向以fromwhere为基准,偏移offset(指针偏移量,可以为负)个字节的位置,函数返回0,如果执行失败(比如offset超过文件自身大小),则不改变fp指向的位置,函数返回非0值。
fromwhere的可能取值为SEEK_CUR,SEEK_END,SEEK_SET
SEEK_SET:文件开头
SEEK_CUR:当前位置
SEEK_END:文件结尾
其中SEEK_SET,SEEK_CUR,SEEK_END依次为0,1,2
应用中一般会用count*sizeof(数据类型)来表示offset,使用该函数后可以使用ftell来得到文件指针位置。(注意文本文件中一个数字1字节,一个小写字母1字节,一个大写字母1字节,一个制表符1字节,可以自己建立文本文件写入一个字符试一下,我在我电脑上测试的是这样)
函数应用实例:
#include<stdio.h>
int main(int argc,char **argv)
{
FILE *fp;
int ch;
fp = fopen("a.txt","r");//a中的数据是ABC123456
if(fp == NULL)
return -1;
printf("%d\n",ftell(fp));//输出刚开始的指针位置
ch = getc(fp);
printf("%c\n",ch);
printf("%d\n",ftell(fp));//读取一个字符,此时指针应该后移1位,输出此时的位置
fseek(fp,3,SEEK_CUR);//向后移动3个字节
printf("%d\n",ftell(fp));//输出此时的位置
ch = getc(fp);//继续读取后面的字符
printf("%c\n",ch);
return 0;
}
//输出结果:0A142
12、rewind
函数原型:void rewind(FILE *fp)
将文件内部的位置指针重新指向流的开头。
注意:不是文件指针而是文件内部的位置指针,随着对文件的读写,文件的位置指针向后移动。而文件指针是指向整个文件,如果不重新赋值文件指针不会改变。
rewind函数的作用等同于(void)fseek(fp,0,SEEK_SET)。