目录
一、文件概述
- 一个文件由一系列彼此有一定联系的数据集合构成。
- 一般把相关的文件放在一个文件夹中。
- 使用时,只要指明文件的名字和存放路径。
- 利用c语言的相关库函数可以对文件中的数据进行读写等基本操作。
1.1、文件类型
- 按存储数据格式可划分为文本文件和二进制文件。
- 文本文件中的数据是以单个字符的形式存放,每个字节存储的是一个字符的ASCII码值,这些彼此相关的字符的集合构成文本文件。
- 二进制文件中的数据是按其在内存中存储样式原样输出到二进制文本进行存储的。即数据在内存中的样子与在二进制文件中的样子一样
文本文件与二进制文件的区别
- 因存储格式的不同,在读写操作时,文本文件是以字节单位进行写入或读出;二进制文件则以变量,结构体等数据块为单位进行读写。
- 一般的,文本文件存储文字信息,一般由可显示字符构成,如说明性的文档,C语言的源程序文件等都是文本文件,二进制文件用于存储非文本数据,如考试成绩或者图形,声音等信息。
1.2、c语言操作文件 -----文件指针
- 在c语言中对文件的操作由文件指针来完成。
- 变量指针指向存储空间
- 文件的指针指向描述有关这个文件的相关信息的一个文件信息结构体,该结构体定义在stdio.h头文件中
声明文件指针的语法格式
- FILE *文件指针的名字 // 功能是声明一个文件指针
- 声明文件指针后,可以使用它进行文件的打开、读写和关闭等基本操作。
1.3、文件缓冲区
- 文件存储在外存储器上,外存的读写速度相对较慢,所以在对文件进行读写操作时,系统会在外存中为文件的输入或输出开辟缓冲区。
- 对文件进行输出时,系统首先把输出的数据填入该文件开辟的缓冲区内,当缓冲区被填满时,就把缓冲区中的内容一次性地输出到对应的文件中,当从某个文件输入数据时,首先将从输入文件中输入一批数据到该文件的缓冲区中,输入语句将从该缓冲区中一次读取数据。当该缓冲区中的数据被读完,将再从输入文件中输入一批数据到缓冲区。
二、文件的打开与关闭
2.1、打开文件的函数 fopen()
定义格式:
- FILE *fp; // 声明fp是一个文件类型的指针
- fp=fopen("文件名",“打开方式”); // 以某种方式打开文件,并使文件指针fp指向该文件
- 作用:以某种指定的方式打开一个指定的文件,并使文件指针fp指向该文件,文件成功打开后,对文件的操作就可以直接通过文件指针fp,若成功打开,fopen()函数返回一个指向FILE类型的指针值(非0值);若指定的文件不能打开,该函数则返回一个空指针值NULL
- fopen()函数包含两个参数,调用时都必须用双引号包括起来,第一个参数("文件名")表示是要打开的文件的文件 名,必须用双引号括起来;如果该参数包含文件的路径,则按路径找到并打开文件;如果省略文件的路径,则在当前目录下打开文件。
fp==fopen("文件名","r+")返回值为0时说明文件打开失败;若文件打开成功,则文件指针fp得到函数是一个非0值
读取数据方式打开文件“aaa.c”
2.2、文件的关闭
关闭文件,就是使文件指针与它指向的文件脱离联系,一般当文件的读写或写操作完成之后,应及时关闭不再使用的文件,这样一方面可以重新分配文件指针去指向其他文件,另外特别是当文件的使用模式为“写”方式时,在关闭文件的时候,系统会首先把文件缓冲区中剩余数据全部输出到文件中,然后再使两者脱离联系,此时如果没有进行正常的关闭文件的操作,而直接结束程序的运行,它会造成缓冲区中剩余数据的丢失。
关闭文件的函数fclose(文件指针)。
fclose()函数只有一个参数"文件指针",它必须是由打开文件的函数fopen()得到,并指向一个已经打开的文件。
作用:关闭文件的指针所指向的文件,指向fclose()函数时,若文件成功关闭,返回0,否则返回-1.
文件关闭语句fclose(fp)
写入数据
保持一个文件的打开状态需要占用内存空间,所以对文件的操作一般应该遵循"晚打开,早关闭"的原则,以避免无畏的浪费。
2.3、文件结束检测
feof()函数用于检测文件是否结束,既适用于二级制文件,也适用与文本文件,其一般适用格式如下:
feof(文件指针) 文件指针指向一个已经打开并正在操作的文件
作用:测试文件指向fp所指向的文件是否已读到文件尾部。若已读到文件尾部,返回值位1;否则返回值为0
进行读文件操作时,需要检测是否读到文件结尾处,用while(!feof(fp))循环语句来控制文件中内容的读取。当前读取的内容不是文件尾部,则feof(fp)的值为0,取非运算后值为1,那么循环继续执行;若已读到文件结尾,则feof(fp)的值为1,取非运算后值为0,循环结束,也即使读文件操作结束。
三、文件的顺序读写
文件顺序读写常用函数
- 字符输入/输出函数:fgetc,fputc
/*
文本中的数据输入输出,可以是以字符位单位,也可以是字符串位单位。
字符位为单位的输入/输出函数:fgetc()和fputc()函数
文件输入函数
fgetc()使用
char ch; // 字符变量
FILE *fp; // 文件指针
ch=fgetc(fp);
作用:该函数从文件所指定的文件中读取一个字符,并把该字符的ASCII值赋给变量ch,执行本函数时,如果是读到文件末尾,则函数
返回文件的结束标志EOF。
注意:文件的输入是指从一个已经打开的文件中读出数据,并将其保存到内存变量中,这里的“输入”是相对内存变量而言的。
EOF
EOF字符常量是文本文件的结束标志,是不可输出字符
在stdio.h中定义为-1,当从文件中读入的字符值等于-1时,表示读入的已不是正常的字符,而是文本文件的结束字符
while(ch!=-1) 等价与 while(ch!=EOF)
判断一个文件结束也可用feof()函数检测
文件输出函数fputc()
fputc(字符,文件指针)
字符:可以是一个普通字符常量,也可以是一个变量名
文件指针:指向一个已经打开的文件。
作用:把“字符”的ASCLL值写入文件指针所指向的文件。若写入成功,则返回字符的ASCLL,否则返回文本文件结束标志EOF
注意:文件输出的是将内存变量中的数据写到文件中,这里的“输出”也是相对内存变量而言的
*/
#include "stdio.h"
#include "stdlib.h" // exit(0) 定义在此文件中
/*
文本中的数据输入输出,可以是以字符位单位,也可以是字符串位单位。
字符位为单位的输入/输出函数:fgetc()和fputc()函数
文件输入函数
fgetc()使用
char ch; // 字符变量
FILE *fp; // 文件指针
ch=fgetc(fp);
作用:该函数从文件所指定的文件中读取一个字符,并把该字符的ASCII值赋给变量ch,执行本函数时,如果是读到文件末尾,则函数
返回文件的结束标志EOF。
注意:文件的输入是指从一个已经打开的文件中读出数据,并将其保存到内存变量中,这里的“输入”是相对内存变量而言的。
EOF
EOF字符常量是文本文件的结束标志,是不可输出字符
在stdio.h中定义为-1,当从文件中读入的字符值等于-1时,表示读入的已不是正常的字符,而是文本文件的结束字符
while(ch!=-1) 等价与 while(ch!=EOF)
判断一个文件结束也可用feof()函数检测
文件输出函数fputc()
fputc(字符,文件指针)
字符:可以是一个普通字符常量,也可以是一个变量名
文件指针:指向一个已经打开的文件。
作用:把“字符”的ASCLL值写入文件指针所指向的文件。若写入成功,则返回字符的ASCLL,否则返回文本文件结束标志EOF
注意:文件输出的是将内存变量中的数据写到文件中,这里的“输出”也是相对内存变量而言的
*/
void main() // 程序入口
{
FILE *fp1,*fp2; // 定义两个文件指针变量
char c;
if((fp1=fopen("file1.txt","w"))==0) // 只读方式新建file.txt文件,并测试是否成功
{
printf("不能打开文件\n");
exit(0); // 强制退出程序
}
printf("输入字符:\n");
while((c=getchar())!='\n') // 接收一个从键盘输入的字符变量c,输入回车符则循环结束
fputc(c,fp1); // 把变量c写到fp1指向的file1.txt文件中
fclose(fp1); // 写入文件结束,关闭文件,使指针fp1和文件脱离关系
if((fp2=fopen("file1.txt","r"))==0)
{
printf("不能打开文件\n");
exit(0); // 强制退出程序
}
printf("输出字符:\n");
while((c=fgetc(fp2))!=EOF) // 从文件file1.txt的开头处读字符存到变量c中
putchar(c); // 把变量c的值输出到屏幕上
printf("\n"); // 换行
fclose(fp2); // 关闭文件
}
- 字符串输入/输出函数:fgets,fputs
#include "stdio.h"
#include "stdlib.h" // exit(0) 定义在此文件中
#include "String.h"
/*
处理大批量数据时使用字符串输入/输出函数fgets(),fputs()
fgets()函数是从文本文件中读取一个字符串
fgets(字符串指针,字符个数n,文件指针)
第一个参数:字符串指针 可以是一个字符数组名,也可以是字符指针,用于存放读出的字符串;
第二个参数:是一个整数,用来指明读出字符的个数
第三个参数:文件指针 指向已经打开的文件
作用:从文件指针指向的文件中读出n-1个字符,并在结尾出加上"\0"组成一个字符串,存入”字符串指针“中,若函数调用成功
则返回字符串的首地址;若读到文件结尾处或调用失败时,则返回字符常量null
fgets(char *s,int n,FILE *fp) 从fp指向的文件中读入n-1个字符,存入字符指针s指向的存储单元
当满足下列条件之一时,读取过程结束:
1、已取了n-1个字符;
2、当前读取的字符是回车符
3、已读到文件末尾
字符串输出函数fputs()
该函数是将一个存放变量中的字符串写到文本文件中
fputs(字符串,文件指针)
第一个参数字符串:可以是一个字符串,也可以是一个字符数组名或指向字符的指针
作用:将“字符串”写到文件指针所指向的文件中,若写入成功,函数的返回值为0,否则,返回一个非零值
注意:向文件中写入的字符串并不包含字符串结束标志符"\0"
例句: char str[10] = {"abc"};
fputs(str,fp)
含义:将字符数组中存放的字符串"abc"写入到fp所指向的文件中,这里写入的是3个字符a,b,c,不包含字符串结束标志"\0"
*/
void main() // 程序入口
{
FILE *fp1,*fp2; // 定义两个文件指针变量
char str[10];
if((fp1=fopen("file2.txt","w"))==0) // 以只写方式新建文件file.txt,并测试是否成功
{
printf("不能创建文件\n");
exit(0); // 强制退出程序
}
printf("输入字符串:\n");
gets(str); // 接收从键盘输入的字符串 10个字节
while(strlen(str)>0)
{
fputs(str,fp1);
fputs("\n",fp1);
gets(str);
}
fclose(fp1); // 写文件结束,关闭文件
if((fp2=fopen("file2.txt","r"))==0) // 以只读方式创建并打开file2.txt文件
{
printf("不能打开文件\n");
exit(0);
}
printf("输出字符串\n");
while((fgets(str,10,fp2))!=0) // 从文件中读取字符串存放到字符数组str并测试是否读完
printf("%s",str); // 输出str数组
printf("\n");
fclose(fp2); // 关闭文件
}
- 格式化输入/输出函数:fscanf,fprintf
#include "stdio.h"
#include "stdlib.h" // exit(0) 定义在此文件中
#include "String.h"
/*
格式化输出函数 fprintf(文件指针,格式串,输出项表)
作用:将输出的内容存放在一个指定的文件中
注意:按“格式串”所描述的格式把输出项写入"文件指针"所指向的文件中,执行这个函数时,若成功,则返回所写的字节数,否则返回一个负数。
格式化输入函数 fscanf(文件指针,格式串,输入项表)
作用:从“文件指针”所指向的文本文件中读取数据,按“格式串”所描述的格式输出到指定的内存单元中。
*/
void main() // 程序入口
{
FILE *fp; // 定义两个文件指针变量
char name1[4][8],name2[4];
int i,score1[4],score2;
// 字符串输出函数部分
if((fp=fopen("file5.txt","w"))==0)
{
printf("不能打开文件\n");
exit(0);
}
printf("输入数据:姓名 成绩\n");
for(i=1;i<4;i++)
{
scanf("%s %d",name1[i],&score1[i]);
fprintf(fp,"%s %d\n",name1[i],&score1[i]);
}
fclose(fp);// 关闭文件
// 字符串输入函数部分
if((fp=fopen("file5.txt","r"))=0) // 以只读方式打开文件测试是否成功
{
printf("不能打开文件\n");
exit(0);
}
printf("输出数据:\n");
while(!feof(fp)) // 检测fp文件指针指向的文件是否被读到末尾
{
fscanf(fp,"%s %d\n",name2,&score2);
printf("%s %d\n",name2,score2);
}
fclose(fp);
}
- 数据块输入/输出函数:fread,fwrite
#include "stdio.h"
#include "stdlib.h" // exit(0) 定义在此文件中
#include "String.h"
/*
二级制文本是以“二进制数据块”为单位进行数据的读写操作,
二进制数据块,就是指在内存中连续存放的具有若干长度的二进制数据,如整型数据,实型数据
数据块输入/输出函数对于存取结构体类型数据尤为方便
c语言提供用来完成对二进制文件进行输入输出操作的函数,称为数据块输入/输出函数fwrite()函数和fread()函数
数据输出函数 ---- fwrite()
这里的"输出",仍是相对于内存变量而言的。fwrite()函数是从内存输出数据到指定的二进制文件中
fwrite(buf,size,count,文件指针)
buf:是输出数据在内存中存放的起始地址,也就是数据块指针;
size:是每个数据块的字节数;
count:用来指定每次写入的数据块个数;
文件指针:是指向一个已经打开等待写入的文件
从以buf为首地址的内存中取出count个数据块(每个数据块为size个字节),写入到“文件指针”指定的文件中,调用成功,该函数
返回实际写入的数据块的个数;出错时返回0值
数据块输入函数 ---- fread()
fread(buf,size,count,文件指针)
buf是输入数据内存中存放的起始地址
其他同上
作用:在文件指针指定的文件中读取count个数据块(每个数据块为size字节),存放到buf指定的内存单元地址中。调用成功
函数返回实际读出的数据块个数;出错或遇到文件末尾时返回0值
*/
void main() // 程序入口
{
FILE *fp; // 定义两个文件指针变量
struct student // 定义结构体数组并初始化
{
char num[8];
int score;
}
stud[] = {{"101",86},{"102",60},{"103",94},{"104",76},{"105",50}},stud1[5];
int i;
if((fp=fopen("stud.bin","wb+"))==0)
{
printf("不能打开文件\n");
exit(0);
}
for(i=0;i<5;i++)
fwrite(&stud[i],sizeof(struct student),1,fp);
rewind(fp);
printf("学号 成绩\n");
while(!feof(fp))
{
fread(&stud1[i],sizeof(struct student),1,fp); // 读取fp指向的文件中的数据并写入到结构体数组stud1中
printf("%s %d\n",stud1[i].num,stud1[i].score); // 向屏幕上输出结构体数组stud1中的数据
}
}
rewind(fp)
将文件内部的位置指针重新指向一个流(文件/数据流)的开头
注意:不是文件指针而是文件内部位置指针,随着文件的读写内部的位置指针向后移
文件指针是指向整个文件
四、文件的随机读写
4.1、位置指针
指当前读或写的数据在文件中的位置。在实际使用中由文件指针充当的
读文件操作:总是从文件位置指针开始读其后的数据,然后位置指针移到尚未读的数据之前;
写文件操作:总是从文件位置指针开始去写,然后移到刚写入数据之后
取文件位置指针的当前值 ---- ftell()函数
ftell()函数用于获取文件位置指针的当前值
ftell(fp) // 指针fp指向一个打开过的正在操作的文件
作用:返回当前文件位置指针fp相对于文件开头的位移量,单位是字节。执行本函数,调用成功返回文件位置指针当前值,否则返回值为-1
注意:该函数适用于二进制文件和文本文件
移动文件位置指针 ---- fseek()函数
该函数用来移动文件位置指针到指定位置上,然后从该位置进行读或写操作,从而实现对文件的随机读写功能
fseek(fp,offset,from);
fp:指向已经打开正在备操作的文件
offset:是文件位置指针的位移量,是一个long型的数据,ANSI C标准规定在数字的末尾加上一个字母L来表示Long型的。
若位移量位正值,表示位置指针的移动是朝着文件尾的方向(从前向后),若位移量位负值,表示位置指针的移动是朝着文件头的方向(从后向前)
from:是起始点,用来指定位移量是以哪个位置位基准
作用:将文件位置指针从from表示的位置移动offset个字节,若函数成功调用,返回值位0,否则返回值非0
置文件位置指针用于文件开头 ---- rewind()
rewind(fp);
作用:将文件位置指针移到文件位置,该函数只有起到移动文件位置指向,并不带回返回值
五、综合应用
#include "stdio.h"
#include "stdlib.h" // exit(0) 定义在此文件中
void main() // 程序入口
{
FILE *fp; // 定义文件指针
char ch[200],c; // 声明一个字符类型的数组 与一个字符类型的变量
int i = 0,j,n;
if((fp=fopen("f1.txt","w+"))==NULL) // 以读写方式新建一个文本文件f1.txt
// 等价于 if((fp=fopen("f1.txe","w+"))==0)
{
printf("不能打开文件f1.txt\n"); // fp文件指针指向已经打开的文件f1.txt fopen()函数返回值为0或null 打印本条语句 返回值为非0时 跳过本条语句
exit(0); // 强制退出程序
}
printf("写入数据到文件f1.txt\n"); // 输出语句
while((c=getchar())!='\n') // 字符类型变量 接收键盘输入的字符
fputc(c,fp); // 字符输出函数 将存放在变量中的字符输出到文本文件中 将字符写入至文件指针指向的文本文件中
rewind(fp); // 文件位置指针 使文件指针指向文件开头处
while((c=fgetc(fp))!=EOF) // 循环读取文件f1.txt中的所有字符并写入字符数组ch中
ch[i++]=c;
fclose(fp); // 关闭文件
if((fp=fopen("f2.txt","W+"))==NULL) // 已读写方式创建一个文本文件f2.txt
{
printf("不能打开文件f2\n"); // fopen返回值为0或者为null时,执行此条语句
exit(0); // 强制退出程序
}
printf("写入数据到f2.txt:\n"); // 输出语句
while((c=getchar())!='\n') // 同一行循环键入字符
fputc(c,fp); // 将字符类型变量c中存储的字符输出至fp文件指针指向的文本文件
rewind(fp);
while((c=fgetc(fp))!=EOF) // 循环读取文件f2.txt中所有字符并写入字符数组ch中
ch[i++]=c;
fclose(fp); // 关闭文件
n=i;
for(j=1;i<n;i++) // 对ch[]数组中的字符进行排序
for(j=0;j<n-i;j++)
if(ch[j]>ch[j+1])
{
c=ch[j];
ch[j] =ch[j+i];
ch[j+1]=c;
}
if((fp=fopen("f3.txt","w+"))==0) // 以读写方式新建一个文本文件
{
printf("\n不能打开文件f3\n"); // 如果fopen返回值为0或者为null时,执行此条语句
exit(0);
}
for(i=0;i<n;i++)
fputc(ch[i],fp);
printf("排序并输出:\n");
rewind(fp);
while((c=fgetc(fp))!=EOF)
putchar(c);
printf("\n");
fclose(fp);
}