c——文件读写
第十三章 文件
学习要求:
1.理解文件的概念
2.掌握文件的打开与关闭的方法
3.掌握文件的读写、定位及出错检测的方法
内容:
C文件概述
1、“文件(file)”:所谓“文件”是指一组相关数据的有序集合。数据以文件的形式存放在外部介质(一般是磁盘、磁带、光盘等)上,在操作系统中是以文件为单位对数据进行管理的。以文件名作为访问文件的标识。
2、C语言把文件看作一个字节序列,即由一连串的字节组成。根据文件中的数据组织形式,数据文件可分为ASCII码文件和二进制文件。
ASCII码文件,又称为“文本文件”(text),其每一个字节存放一个ASCII码。
二进制文件,把内存中的数据按其在内存中的存储形式存放在磁盘上。
例:十进制整数10000,在内存中占两个字节,其存放形式是:00100111,00010000。在二进制文件中也按这种方式存放。
但是,在ASCII文件中,十进制整数10000存放为31H、30H、30H、30H、30H,占五个字节,它们分别是1、0、0、0、0、0字母的ASCII码。
3、按照操作系统对磁盘文件的读写方式,文件可以分为“缓冲文件系统”和“非缓冲文件系统”。
缓冲文件系统:操作系统在内存中为每一个正在使用的文件开辟一个读写缓冲区。从内存向磁盘输出数据必须先送到内存中的缓冲区,装满缓冲区后才一起送到磁盘上。如果从磁盘向内存读入数据,则一次从磁盘文件将一批数据输入到内存缓冲区,然后再从缓冲区逐个地将数据送到程序数据区。
非缓冲文件系统:指操作系统不自动开辟确定大小的读写缓冲区,而由程序为每个文件设定缓冲区。
在UNIX系统下,用缓冲文件系统来处理文本文件,用非缓冲文件系统处理二进制文件。ANSI C标准只采用缓冲文件系统。
在C语言中,没有输入输出语句,对文件的读写都是用库函数来实现的。本章只介绍ANSI C标准规定的缓冲文件系统。
文件类型指针
缓冲文件系统中,每一个使用的文件都在内存中开辟一个“文件信息区”,用来存放文件的相关信息(文件的名字、文件当前的读写位置、文件操作方式等)。这些信息保存在一个结构体变量中,该结构体是由系统定义的,取名为FILE。Turbo C 3.0 在stdio.h文件中有以下文件类型的声明:
typedef struct {
int level; /* 缓冲区“满”或“空”的程度 */
unsigned flags; /* 文件状态标志 */
char fd; /* 文件描述符*/
unsigned char hold; /* 如无缓冲区不读取字符 */
int bsize; /* 缓冲区的大小 */
unsigned char *buffer; /* 数据缓冲区的位置*/
unsigned char *curp; /* 指针,当前的指向 */
unsigned istemp; /* 临时文件,指示器 */
short token; /* 用于有效性检查 */
} FILE;
定义文件指针变量的一般形式为:
FILE *文件结构指针变量名
例如:FILE *fp;
注意:只有通过文件指针,才能调用相应的文件。
文件的打开(fopen函数)
文件操作的过程:对磁盘文件的操作必须“先打开,后读写,最后关闭”。
“打开”文件的含义:以某中方式从磁盘上查找指定的文件或创建一个新文件。
ANSI C规定了标准输入输出函数库,用 fopen()函数打开文件。fopen()函数的调用方式一般为:
FILE *fp;
fp=fopen(文件名,使用文件方式);
例如:
FILE *fp;
aaaafp = fopen("file1","r");
表示要打开名字为file1的文件,使用文件方式为“读入”,如果打开成功,返回一个指向file1文件的指针;如果打开失败,返回一个NULL指针。
使用文件方式见下表:
使用文件方式 |
含义 |
"r"(只读) | 为输入打开一个文本文件 |
"w"(只写) | 为输出打开一个文本文件 |
"a"(追加) | 为追加打开一个文本文件 |
"rb"(只读) | 为输入打开一个二进制文件 |
"wb"(只写) | 为输出打开一个二进制文件 |
"ab"(追加) | 为追加打开一个二进制文件 |
"r+"(读写) | 为读/写打开一个文本文件 |
"w+"(读写) | 为读/写创建一个文本文件 |
"a+"(读写) | 为读/写打开一个文本文件 |
"rb+"(读写) | 为读/写打开一个二进制文件 |
"wb+"(读写) | 为读/写创建一个二进制文件 |
"ab+"(读写) | 为读/写打开一个二进制文件 |
说明:
1、用"r"方式打开的文件只能用于向计算机输入而不能用作向该文件输出数据,而且该文件应该已经存在,不能用"r"方式打开一个不存在的文件(即输入文件),否则出错。
2、用"w"方式打开的文件只能用于向该文件写数据(即输出文件),而不能用来向计算机输入。如果原来不存在该文件,则在打开时新建一个文件,如果该文件存在,则先删除该文件,然后重新建立一个新文件。
3、如果希望向文件尾添加新数据(不删除原有数据),则应该用"a"方式打开。但要求此时文件必须存在,否则出错。
4、用"r+"、"w+"、"a+"方式打开的文件即可以用来输入数据,也可以用来输出数据。
5、如果不能实现打开文件的任务,fopen()函数将带回一个出错信息。用带"r"的方式("r"、"rb"、"r+"、"rb+")打开文件时,若文件不存在,则返回NULL指针。
常用以下方式打开文件:
FILE *fp;
if ((fp=fopen("file1", "r")) ==NULL )
{
printf("cannot open this file\n");
exit(0);
}
即如果有错就在终端上输出"cannot open this file"。exit()函数的作用是关闭所有文件,终止正在执行的程序。
6、在向计算机输入文本文件时,将回车换行符转换为一个换行符,在输出时把换行符转换为回车和换行两个字符。在用二进制文件时,不进行转换。
文件的关闭(fclose函数)
在使用完一个文件后应该关闭它,“关闭”文件就是使文件指针与文件脱离,此后不能再通过该指针对原来与其相联系的文件进行读写操作。应养成在程序终止前关闭所有文件的习惯。
用fclose函数关闭文件。fclose函数调用的一般形式为:
fclose(文件指针)
例如:
fclose(fp);
fclose函数也带回一个返回值,当顺利关闭文件时,返回0,否则返回EOF(-1)。
文件的读写
当文件打开后,就可以对它进行读写了。常用的读写函数如下所述。
1、fputc函数和fgetc函数(putc函数和getc函数)
(1)、fputc函数
把字符写入到磁盘文件,一般的调用方式为:
fputc(ch,fp)
把字符(ch的值)写入fp所指向的文件中去。成功时返回字符ch的ASCII码,失败时返回
EOF(在stdio.h中,符号常量EOF的值等于-1)。
(2)、fgetc()函数
从指定文件读入一个字符。fgetc函数的调用形式为:
ch=fgetc(fp);
从fp所指向的文件中读一个字符,返回读得的字符给变量ch。对于文本文件,遇文件尾时返回文件结束标志EOF。对于二进制文件,用feof(fp) 判别是否遇文件尾,feof(fp)=1说明遇文件尾。
从文本文件中顺序读入文件内容,并在屏幕上显示出来,可以用:
ch = fgetc(fp);
while(ch != EOF)
{
putchar(ch);
ch = fgetc(fp);
}
从二进制文件中顺序读入文件内容,可以用:
while(!feof(fp))
{
ch = fgetc(fp);
....
}
这种方法也适用于文本文件。
(3)、fputc函数和fgetc函数应用举例
例子13_1 从键盘输入一些字符,逐个把它们送入磁盘文件,直到从键盘输入#为止。
例子13_2 将一个磁盘文件的内容复制到另一个磁盘文件。
fread函数和fwrite函数
fread函数和fwrite函数用来读写一个数据块。它们的一般调用方式为:
fread(buffer,size,count,fp);
fwrite(buffer,size,count,fp);
其中:
buffer:是一个指针。对fread来说,它是读入数据的存放地址。对fwrite来说,是要输出数据的地址。
size:要读写的字节数。
count:要进行读写多少个size字节的数据项。
fp:文件型指针。
如果以二进制形式打开文件,用fread函数和fwrite函数就可以读写任何类型的信息,例如:
fread(f,4,2,fp);
其中f是一个实型数组名。一个实型变量占4个字节。这个函数从fp所指向的文件读入2个4个字节的数据,存储到数组f中。
如果有如下的结构体类型:
struct student_type
{
char name[10];
int num;
int age;
char addr[30];
}stu[40];
结构体数组stu有40个元素,每一个元素用来存放一个学生的数据。假设学生的数据已经存放在磁盘文件中,可以用下面的for语句和fread函数读入40个学生的数据:
for(i=0; i<40; i++)
fread(&stu[i], sizeof(struct student_type), 1, fp);
或:
fread(&stu[i], sizeof(struct student_type), 40, fp);
同样,以下程序可以将内存中的学生数据输出到磁盘文件中去:
for(i=0; i<40; i++) /* 每次写一个学生 */
fwrite(&stu[i], sizeof(struct student_type), 1, fp);
或者只写一次
fwrite(stu, sizeof(struct student_type), 40, fp);
例子13_3 从键盘上输入一批学生数据,然后存储到磁盘上。
fprintf函数和fscanf函数
fprintf函数、fscanf函数与printf函数、scanf函数的作用相仿,都是格式化读写函数。fprintf和fscanf函数的读写对象是磁盘文件,而printf和scanf函数的读写对象是终端。
它们的一般调用格式为:
fprintf(文件指针,格式字符串,输出列表);
fscanf (文件指针,格式字符串,输入列表);
除增加“文件指针”外,其他与printf()/scanf()用法相同。
例如:
fprintf(fp,"%d,%6.2f",i,t);
它的作用是将整型变量i和实型变量t的值按%d和%6.2f的格式输出到fp所指向的文件中。如果i=3,t=4.5,则输出到磁盘文件上的是以下字符串:
3,4.50
同样,用fscanf函数可以从磁盘文件上读入ASCII字符:
fscanf(fp,"%d,%f",&i,&t);
磁盘文件上如果有以下字符:3,4.5 则将磁盘文件的数据3送给变量i,4.5送给变量t。
用fprintf和fscanf函数对磁盘文件操作,由于在输入时要将ASCII码转换为二进制形式,在输出时又要将二进制转换为字符,花费时间比较多,因此,在内存与磁盘频繁交换数据的情况下,最好不用fprintf和fscanf函数,而用fread和fwrite函数。
其他读写函数
1、putw和getw函数
putw和getw函数用来对磁盘文件读写一个字(整数)。例如:
putw(10,fp); /* 整数10写入文件fp */
i=getw(fp); /* 从文件fp读一个整数给变量i */
2、fgets和fputs函数
fgets函数的作用是从指定文件读入一个字符串。例如:
fgets(str, n,fp) /* 从文件fp读n-1个字节到str,str最后一个字节加'\0'*/
fputs函数的作用是向指定的文件输出一个字符串。例如:
fputs(str,fp) /* 把字符串str写入fp */
文件的定位
文件中有一个位置指针,指向当前读写的位置。每当进行一次读写后,该指针自动指向下一个字符的位置。可以用ftell()函数获得当前的位置指针,也可以用rewind()/fseek()函数改变位置指针,使其指向需要读写的位置。
1、rewind函数
一般的使用形式为:rewind(fp);作用:使文件fp的位置指针指向文件开始。
例子13_4 把一个文件的内容显示在屏幕上,并同时复制到另一个文件。
2、fseek函数和随机读写
对流式文件可以进行顺序读写,也可以进行随机读写,关键在于控制文件的位置指针。
用fseek函数可以实现改变文件的位置指针。fseek函数的调用形式为:
fssek (文件类型指针,位移量,起始点);
功能:把文件的位置指针从起始点开始,移动指定位移量的字节数。成功返回0,失败返回非0。
起始点 | 符号常量 | 值 |
文件开始位置 | SEEK_SET | 0 |
当前位置 | SEEK_CUR | 1 |
文件尾 | SEEK_END | 2 |
例子13_5 在磁盘文件stud_dat上,存有10个学生(0~9)的数据,读出1、3、5、7、9号学生数据,并在屏幕上显示出来。
3、ftell函数
ftell函数的作用是得到流式文件中的当前位置,用相对于文件开头的位移量来表示。若失败则返回值为-1L。
例如:
i=ftell(fp);
if(i==-1L) printf("error\n");
变量i存放当前位置,如调用函数时出错(如不存在fp文件),则输出"error"。
出错的检测
C 标准提供一些函数用来检查输入输出函数调用中的错误。
1、ferror函数
在文件操作时,如果出错,除了操作函数的返回值有所反应外(如fopen()函数返回NULL),还可以用ferror函数获得是否出错。它的一般调用形式为:
ferror(fp)
功能:若上一次文件操作未出错,返回0;否则返回非0。
2、clearerr函数
clearerr函数的作用是使文件错误标志和文件结束标志置为0。 文件操作出现错误后,ferror(fp)函数值为一个非0值,该错误信息将一直保留在系统中,在调用clearerr(fp)函数后,ferror(fp)函数值变成0。
文件输入输出小结
常用的缓冲文件系统函数
分类 |
函数名 |
功能 |
打开文件 |
fopen() |
打开文件。 |
关闭文件 |
fclose() |
关闭文件。 |
文件定位 |
fseek() rewind() ftell() |
改变文件位置指针位置 使文件位置指针重新置于文件开头 返回文件位置指针的当前值 |
文件读写 |
fgetc(),getc() fputc(),putc() fgets() fputs() getw() putw() fread() fwrite() fscanf() fprintf() |
从指定文件取得一个字符。 把字符输出到指定文件。 从指定文件读取字符串。 把字符串输出到指定文件。 从指定文件读取一个字(int型)。 把一个字(int型)输出到指定文件。 从指定文件中读取数据项。 把数据项写到指定文件。 从指定文件按格式输入数据。 按指定格式将数据写到指定文件中。 |
文件状态 |
feof() ferror() clearerr() |
若到文件末尾,函数值为“真”(非0)。 若对文件操作出错,函数值为“真”(非0)。 使ferror和feof函数值置零。 |