文件概述
文件是指 一组相关的数据的有序集合,文件通常驻留在外部存储介质(如磁盘)上的,在使用时才调入内存。可以从不同的角度对文件进行分类。
从用户的角度,文件可以分为普通文件和设备文件两种。
普通文件
是指驻留在磁盘或其他的外部介质上的一个数据集,可以是源文件,目标文件,可执行程序,也可以是一组带输入处理的原始数据,或者是一组输出结果;设备文件
是指与主机相关联的各种设备,如显示器,打印机,键盘等。从文件编码的角度,文件可以分为ASCII码文件和二进制文件两种。ASCII码文件也称为文本文件,这种文件在磁盘中存储
每个字符对应一个字节
,用于存放字符的ASCII码,例如源程序文件,记事本文件等都是文本文件;二进制文件是按字符的二进制编码存放的。
文件指针
在C语言中,用一个指针变量指向一个文件,该指针称为文件指针。通过文件指针可以对文件各种操作。定义该指针的一般形式为:
FILE *指针变量标识符
说明:FILE是有系统定义的结构体,其中含有文件名,文件状态和文件的当前位置等信息,在编写源程序时不必关心FILE结构体细节。
例如:FILE *fp
含义:fp是指向结构体FILE的指针变量,通过fp即可找到存放某个文件信息的结构体信息,按结构体信息找到该文件,可以实施对文件的操作。习惯上把fp称为指向一个文件的指针,简称文件指针
文件的打开和关闭
文件在进行读写操作之前要打开,使用后要关闭。打开文件实际上是建立文件的各种有关信息,并使文件指针指向该文件,以便进行其他操作。关闭文件则是断开文件指针与文件之间的联系,禁止对该文件进行操作。
在C语言中,文件操作都是由库函数完成的。
文件打开函数(fopen)
fopen函数用于打开一个文件,其调用形式一般为:
文件指针名=fopen(文件名,文件打开方式);
例如:FILE *fp;
fp = fopen("c:\file1.dat","rb");
以只读方式打开C盘根目录下的二进制文件file1.dat。两个反斜线""中的第一个表示转义字符,第二个表示根目录。“rb”是文件的打开方式,C语言中的文件打开方式如下表所示
“rt” | 只读打开一个文本文件,只允许读数据 |
---|---|
“wt” | 只写打开或建立一个文本文件,只允许写数据 |
“at” | 追加打开一个文本文件,并在文件末位写数据 |
“rb” | 只读打开一个二进制文件,只允许读数据 |
“wb” | 只写打开或建立一个二进制文件,只允许写数据 |
“ab” | 追加打开一个二进制文件,并在文件末尾写数据 |
“rt+” | 读写打开一个文本文件,允许读写 |
“wt+” | 读写打开或建立一个二进制文件,允许读写 |
“at+” | 读写打开一个文本文件,允许读,或在文件末尾追加数据 |
“rb+” | 读写打开一个二进制文件,允许读和写 |
“wb+” | 读写打开或建立一个二进制文件,允许读和写 |
“ab+” | 读写打开一个二进制文件,允许读,或在文件末尾追加数据 |
+:读和写
- 用“r”打开一个文件,
文件必须存在
,且只能从该文件读取信息。 - 用"w"打开一个文件只能向该文件写入。若打开文件不存在,则以指定的文件名建立该文件,若打开的文件已经存在,则将该文件删去,重建一个新文件。
- 若要向一个已经存在的文件末尾追加新的信息,用“a”方式打开文件。以追加的方式打开文件时,文件位置指针自动移向文件末尾。
- 在打开一个文件时,如果出错,fopen函数返回一个空指针NULL。据此在程序中可以判断是否能顺利打开文件。例如
if((fp=fopen("c:\file1.dat","rb"))==NULL){
printf("
error on open c:\file1.dat !");
return ;
}
如果返回的指针为空,则不能正确打开C盘根目录下的file1.dat文件,给出提示信息error on open c:file1.dat !,退出程序。
文件关闭函数(fclose)
文件使用完毕,应该关闭该文件,断开文件指针与文件之间的联系。fclose函数调用的一般形式为:
fclose(文件指针);
例如:fclose(fp);
说明:正常关闭文件操作,fclose函数返回值为0;如返回值非零值,则表示有错误发生。
文本文件的读写
操作函数要求包含头文件stdio.h
字符读写函数
字符读写函数以字符(字节)为单位,每次可从文本文件中读出或写入一个字符。
1.字符读函数(fgetc)
格式:字符变量=getc(文件指针);
功能:从指定的文件中读取一个字符
例如:ch=getc(fp); //从打开的文件fp中读取一个字符并存入ch中
2.字符写函数(fputc)
格式:fputc(字符,文件指针);
功能:把一个字符写入指定的文件中。
说明:
(1)待写入的字符 可以是字符串常量或变量。
例如:fputc('a',fp);//是把字符'a'写入fp所指文件中。
(2)被写的文件可以用写,追加方式打开,用写方式打开一个已存在的文件时将清除原有的文件内容,写入字符从文件的首部开始;如果需要保留原有的文件内容,希望写入的字符在文件末尾存放,必须以追加
方式打开文件
(3)每写入一个字符,文件内部位置指针向后移动一个字节
#include <stdio.h>
void main(){
FILE *fpin,*fpout;
char ch;
if ((fpin=fopen("d:\beauty.txt","wt"))==NULL)
{
printf("Cannot open beauty.txt!
");
return ;
}
printf("Please input a string:
");
ch = getchar();
while(ch!='
'){
fputc(ch,fpin);
ch = getchar();
}
fclose(fpin);
if ((fpout=fopen("d:\beauty.txt","rt"))==NULL)
{
printf("Cannot read the beauty.txt!
");
return ;
}
ch = fgetc(fpout); //将文件中的第一个字符读入ch
while(ch!=EOF){
putchar(ch);
ch=fgetc(fpout);
}
fclose(fpout);
}
字符串读写函数(fgets和fputs)
1.读字符串函数(fgets)
格式:fgets(字符数组名,n,文件指针)
功能:从指定文件中读取一个字符串存入字符数组中。
说明:n表示从文件中读出的字符串不超过n-1个字符,在读入的最后一个字符后自动加上字符串结束标志‘ ’。
例如:fgets(str,n,fp); //从fp所指的文件中读出
n-1个字符存入字符数组str中。
#include <stdio.h>
void main(){
FILE *fpout;
char ch;
char str[11];
if ((fpout=fopen("d:\beauty.txt","rt"))==NULL)
{
printf("Cannot read the beauty.txt!
");
return ;
}
fgets(str,11,fpout);//从fp所指的文件中读入一个含10个字符的字符串赋给str
printf("%s
",str);
fclose(fpout);
}
2.写字符串函数(fputs)
格式:fputs(字符串,文件指针);
#include <stdio.h>
void main(){
FILE *fpout;
char ch;
char st[20];
if ((fpout=fopen("d:\beauty.txt","at+"))==NULL)
{
printf("Cannot read the beauty.txt!
");
return ;
}
printf("please input a string:
");
scanf("%s",st);
fputs(st,fpout); //将st表示的字符串追加到fp所指的文件中
fclose(fpout);
}
二进制文件的读写
数据块读写函数(fread和fwrite)
格式:fread(buffer,size,count,fp);
功能:读数据块
格式:fwrite(buffer,size,count,fp);
功能:写数据块
(1)buffer
:是一个指针,在fread函数中表示输入数据的首地址,在fwrite函数中表示存放输入数据的首地址。
(2)size
:数据块的字节数。
(3)count
:要读写的数据块块数。
(4)fp
:文件指针
例如:fread(fa,4,5,fp);
含义:从fp所指的文件中一次读4个字节送入4个字节送入指针fa中,连续读5次。
#include <stdio.h>
struct stud{
char name[10];
int num;
}sw[5],sr[5],*pw,*pr;
void main(){
FILE *fp;
char ch;
int i;
if ((fp=fopen("d:\beauty.dat","wb+"))==NULL) //以读写方式打开文件
{
printf("Cannot read the beauty.txt!
");
return ;
}
pw = sw; //指针pw指向数组sw
pr = sr; //指针pr指向数组sr
printf("input data : name num
");
for (i=0;i<5;i++)
scanf("%s%d",sw[i].name,&sw[i].num);
//将指针pw指向的5个数组元素写入fp所指的文件中
fwrite(pw,sizeof(struct stud),5,fp);
rewind(fp); //将文件内部位置指针移到文件首部
fread(pr,sizeof(struct stud),5,fp);
//从fp所指的文件中读出数据存入指针pr指向的数组中
printf("
name num
");
for (i=0;i<5;i++)
{
printf("%s %5d
",sr[i].name,sr[i].num);
fclose(fp);
}
}
程序以读写的方式打开d盘二进制文件st.dat,输入5个学生数据并写入文件中,然后把文件内部位置指针移到文件首部,读出5个学生数据显示到屏幕上
格式化读写函数(fscanf和fprinf)
fscanf函数和fprinf都是格式化读写函数,他们的读写对象不是键盘和显示器,而是磁盘文件。这两个函数的调用格式为:
fscanf(文件指针,格式字符串,输入列表);
fprintf(文件指针,格式字符串,输出列表);
例如:
fscanf(fp,"%d%s",&i,s);
fprintf(fp,"%d%c",j,ch);
#include <stdio.h>
struct stud{
int num;
char name[20];
}sw[5],sr[5],*pw,*pr;
void main(){
FILE *fp;
if ((fp = fopen("d:\你好.txt","wt+"))==NULL) //缺了wt+中的“+”将无法读取文件
{
printf("Cannot read 你好.txt");
return ;
}
pw = sw;
pr = sr;
printf("input name and num:
");
for (int i=0;i<5;i++)
{
scanf("%s%d",sw[i].name,&sw[i].num);
}
for (i=0;i<5;i++,pw++)
{
fprintf(fp,"%s %d
",pw->name,pw->num);
}
rewind(fp); //将文件内部位置指针移到文件首部
for(i=0;i<5;i++,pr++){
fscanf(fp,"%s %d",pr->name,&pr->num); //&符号必须加上,否则会报错,找不到该地址
}
printf("name num
");
for(i=0;i<5;i++){
printf("%s %d
",sr[i].name,sr[i].num);
}
fclose(fp);
}
fscanf和fprintf函数每次只读写一个结构体数组元素,因此采用了循环语句来读写全部的数组元素。
判断文件是否结束函数(feof)
如果结束,值为1,否则,为0
feof函数可用于判断二进制文件是否结束,也可以判断文本文件是否结束
#include <stdio.h>
struct stud{
int num;
char name[20];
}sw[5],sr[5],*pw,*pr;
void main(){
FILE *fpin,*fpout;
char ch;
if ((fpin = fopen("d:\c1.txt","rt"))==NULL)
{
printf("Cannot read c1.txt");
return ;
}
if ((fpout=fopen("d:\c2.txt","wt"))==NULL)
{
printf("Cannot write c2.txt");
return ;
}
ch = fgetc(fpin);
while(!feof(fpin)){
putchar(ch);
fputc(ch,fpout);
ch = fgetc(fpin);
}
fclose(fpin);
fclose(fpout);
}
ferror函数
在调用各种输入输出函数(如 putc.getc.fread.fwrite等)时,如果出现错误,除了函数返回值有所反映外,还可以用ferror函数检查。 它的一般调用形式为 ferror(fp);如果ferror返回值为0(假),表示未出错。如果返回一个非零值,表示出错。应该注意,对同一个文件每一次调用输入输出函数,均产生一个新的ferror函 数值,因此,应当在调用一个输入输出函数后立即检 查ferror函数的值,否则信息会丢失。在执行fopen函数时,ferror函数的初始值自动置为0。
#include <stdio.h>
void main(){
FILE *stream;
stream = fopen("d:\c3.txt","wt");
getc(stream);
if (ferror(stream))
{
printf("Error reading from c3.txt
");
clearerr(stream);
}
fclose(stream);
}
文件内部指针定位
移动文件内部位置指针的函数主要有两个:rewind函数和fseek函数
格式:rewind(文件指针);
功能:把文件内部位置指针移到文件首部
格式:fseek(文件指针,位移量,起始点);
功能:移动文件内部位置指针到指定位置
说明:
(1)文件指针:指向被操作的文件。
(2)位移量:移动的字节数,要求位移量时long型数据,以便在文件长度大于64KB时不会出错
(3)起始点:表示从何处开始计算位移量。起始点有三种:文件首部,当前位置和文件尾
文件起始点表示法
起始点含义 | 表示符号 | 数字表示 |
---|---|---|
文件首部 | SEEK_SET | 0 |
当前位置 | SEEK_CUR | 1 |
文件末尾 | SEEK_END | 2 |
例如:fseek(fp,100L,0); .//把文件内部位置指针移到里文件首部100个字节处
fseek函数一般用于二进制文件,因为在文本文件中要对字节进行转换,计算的位置不易确定。
#include <stdio.h>
struct stud{
int num;
char name[20];
}s;
void main(){
FILE *fp;
if ((fp=fopen("d:\beauty.dat","rb+"))==NULL)
{
printf("Cannot read beauty.dat
");
return ;
}
rewind(fp);
fseek(fp,sizeof(stud),0); //指针指向第二个学生信息首部
fread(&s,sizeof(stud),1,fp);//读出第二个学生信息存入s中
printf("%s %d
",s.name,s.num);
fclose(fp);
}
ftell函数
ftell函数用于获得文件当前位置指针的位置,函数返回文件中当前位置指针相对于文件的首部的字节数。若fp已指向一个正确打开的文件,ftell函数调用方式如下:
long t;
t = ftell(fp);
#include <stdio.h>
struct stud{
int num;
char name[20];
}s;
void main(){
FILE *fp;
int n;
long t;
if ((fp=fopen("d:\beauty.dat","rb+"))==NULL)
{
printf("Cannot read beauty.dat
");
return ;
}
fseek(fp,0L,SEEK_END); //将位置指针移到文件末尾
t = ftell(fp); //文件当前位置指针相对于文件首的字节数,实际上是文件长度
n = t/sizeof(stud); //以结构体为单位的数据个数
printf("%ld %d
",t,n);
fclose(fp);
}
本章小结
磁盘文件是存储在外部介质上的程序或数据的集合;C程序中的文件是由磁盘文件和设备文件组成的。数据文件是磁盘文件的一种,其引入的主要目的一是可是数据永久的保存在外存储器上,二是可以方便的进行数据的输入和保存。
根据文件的组成形式,数据文件可分为文本文件和二进制文件两种,主要内容如下:
1.C文件
文件类型FILE是用typedef定义的有关文件信息的一种结构体类型,不是C语言提供类型,可以在其基础之上定义文件指针。
2.C文件操作函数
C语言对文件的操作都是用库函数来实现的,利用C语言提供的库读写函数可以实现文件信息的输入,输出,修改等操作。
函数名 | 函数功能 |
---|---|
fopen函数 | 用于打开文件。 |
fclose函数 | 用于关闭文件 |
fputc函数 | 指定文件的进行一个字符输入的操作 |
fgetc函数 | 指定文件的进行一个字符输出的操作 |
fputs函数 | 指定文件的进行一个字符串输入的操作 |
fgets函数 | 指定文件的进行一个字符串输出的操作 |
fprintf函数 | 对指定的文件进行格式化操作 |
fscanf函数 | 对指定的文件进行格式化操作 |
fread函数 | 对指定的文件进行成块读操作 |
fwrire函数 | 对指定的文件进行成块写操作 |
rewind函数 | 把文件内部指针移动到文件首部 |
fseek函数 | 移动文件内部指针到指定位置 |
ftell函数 | 获得文件当前位置指针的位置 |