第十三章 文 件 13.1 C文件概述 文件:文件指存储在外部介质(如磁盘磁带)上数据的集合。 操作系统是以文件为单位对数据进行管理的。
文件的分类 ●从用户观点: 特殊文件(标准输入输出文件或标准设备文件)。 普通文件(磁盘文件)。 ●从操作系统的角度看,每一个与主机相连的输入 输出设备看作是一个文件。 例:输入文件:终端键盘 输出文件:显示屏和打印机 (1)根据文件的内容,可分为程序文件和数据文件,程序文件又可分为源文件、目标文件和可执行文件。 (2)根据文件的组织形式,可分为顺序存取文件和随机存取文件。 (3)根据文件的存储形式,可分为ASCII码文件和二进制文件。 ASCII码文件的每1个字节存储1个字符,因而便于对字符进行逐个处理。但一般占用存储空间较多,而且要花费转换时间(二进制与ASCII码之间的转换)。 二进制文件是把内存中的数据,原样输出到磁盘文件中。可以节省存储空间和转换时间,但1个字节并不对应1个字符,不能直接输出字符形式。 C语言对文件的处理方法: 缓冲文件系统:系统自动地在内存区为每一个正在使用的文件开辟一个缓冲区。用缓冲文件系统进行的输入输出又称为高级磁盘输入输出。 非缓冲文件系统:系统不自动开辟确定大小的缓冲区,而由程序为每个文件设定缓冲区。用非缓冲文件系统进行的输入输出又称为低级输入输出系统。 说明: 在UNIX系统下,用缓冲文件系统来处理文本文件,用非缓冲文件系统来处理二进制文件。 ANSI C 标准只采用缓冲文件系统来处理文本文件和二进制文件。 C语言中对文件的读写都是用库函数来实现。 13.2 文件类型指针 Turbo C在stdio.h文件中有以下的文件类型声明: typedef struct { shortlevel; /*缓冲区“满”或“空”的程度*/ unsignedflags; /*文件状态标志*/ charfd; /*文件描述符*/ unsignedcharhold; /*如无缓冲区不读取字符*/ shortbsize; /*缓冲区的大小*/ unsignedchar*buffer;/*数据缓冲区的位置*/ unsignedar*curp;/*指针,当前的指向*/ unsignedistemp;/*临时文件,指示器*/ shorttoken;/*用于有效性检查*/}FILE; 在缓冲文件系统中,每个被使用的文件都要在内存中开辟一 FILE类型的区,存放文件的有关信息。 FILE类型的数组: FILE f[5];定义了一个结构体数组f,它有5个元素,可以用来存放5个文件的信息。 文件型指针变量: FILE *fp;fp是一个指向FILE类型结构体的指针变量。可以使fp指向某一个文件的结构体变量,从而通过该结构体变量中的文件信息能够访问该文件。如果有n个文件,一般应设n个指针变量,使它们分别指向n个文件,以实现对文件的访问。 13.3 文件的打开与关闭 一.文件的打开(fopen函数) 函数调用: FILE *fp; fp=fopen(文件名,使用文件方式); ①需要打开的文件名,也就是准备访问的文件的名字; ②使用文件的方式(“读”还是“写”等); ③让哪一个指针变量指向被打开的文件。
二.文件的关闭(fclose函数) 函数调用: fclose(文件指针); 函数功能: 使文件指针变量不指向该文件,也就是文件指针变量与文件“脱钩”,此后不能再通过该指针对原来与其相联系的文件进行读写操作。 返回值: 关闭成功返回值为0;否则返回EOF(-1) 。 13.4 文件的读写 一、字符输入输出函数(fputs()和fgets()) 1.fputs函数 函数调用: fputs ( ch,fp ) ; 函数功能: 将字符(ch的值)输出到fp所指向的文件中去。 返回值: 如果输出成功,则返回值就是输出的字符; 如果输出失败,则返回一个EOF。 2.fgets函数 函数调用: ch=fgets(fp); 函数功能: 从指定的文件读入一个字符,该文件必须是以读或读写方式打开的。 返回值: 读取成功一个字符,赋给ch。 如果遇到文件结束符,返回一个文件结束标志EOF 。 常见的读取字符操作 从一个文本文件顺序读入字符并在屏幕上显示出来: ch = fgetc(fp); while(ch!=EOF) { putchar(ch); ch = fgetc(fp); } 注意:EOF不是可输出字符,因此不能在屏幕上显示。由于字符的ASCII码不可能出现-1,因此EOF定义为-1是合适的。当读入的字符值等于-1时,表示读入的已不是正常的字符而是文件结束符。 常见的读取字符操作 从一个二进制文件顺序读入字符: while(!feof(fp)) { ch = fgetc(fp); } 注意:ANSI C提供一个feof()函数来判断文件是否真的结束。如果是文件结束,函数feof(fp)的值为1(真);否则为0(假)。以上也适用于文本文件的读取。 #include <stdlib.h> #include <stdio.h> void main(void) { FILE *fp; char ch,filename[10]; scanf("%s",filename); if((fp=fopen(filename,"w"))==NULL) { printf("cannot open file\n"); exit(0); /*终止程序*/ } ch=getchar( ); /*接收执行scanf语句时最后输入的回车符 */ ch=getchar( ); /* 接收输入的第一个字符 */ while(ch!='#’) { fputc(ch,fp);putchar(ch); ch=getchar(); } fclose(fp); }
#include <stdlib.h> #include <stdio.h> main( ) { FILE *in,*out; char ch,infile[10],outfile[10]; printf("Enter the infile name:\n"); scanf("%s",infile); printf("Enter the outfile name:\n"); scanf("%s",outfile); if((in=fopen(infile,"r"))==NULL) { printf("cannot open infile\n"); exit(0); } if((out=fopen(outfile,"w"))==NULL) { printf("cannot open outfile\n"); exit(0); } while(!feof(in))fputc(fgetc(in),out); close(in); fclose(out); }
#include <stdlib.h> #include <stdio.h> main(int argc,char *argv[ ]) { FILE *in,*out; char ch; if (argc!=3) { printf("You forgot to enter a filename\n"); exit(0); } if((in=fopen(argv[1],"rb"))==NULL) { printf("cannot open infile\n"); exit(0); } if((out=fopen(argv[2],"wb"))==NULL) { printf("cannot open outfile\n"); exit(0); } while(!feof(in)) fputc(fgetc(in),out); fclose(in); fclose(out); }
二、数据块读写函数(fread()和fwrite()) 函数调用: fread (buffer,size,count,fp); fwrite(buffer,size,count,fp); 参数说明: buffer:是一个指针。 对fread 来说,它是读入数据的存放地址。 对fwrite来说,是要输出数据的地址(均指起始地址)。 size: 要读写的字节数。 count: 要进行读写多少个size字节的数据项。 fp: 文件型指针。 使用举例: 若文件以二进制形式打开: fread(f,4,2,fp); 此函数从fp所指向的文件中读入2个4个字节的数据,存储到数组f中。 使用举例: 若有如下结构类型: struct student_type { char name[10]; int num; int age; char addr[30];}stud[40]; } 可以用fread和fwrite来进行数据的操作: for(i=0;i<40;i++) fread(&stud[i],sizeof(struct student-type),1,fp); for(i=0;i<40,i++) fwrite(&stud[i],sizeof(struct student-type),1,fp); 使用举例: 例13.3从键盘输入4个学生的有关数据,然后把它们转存到磁盘文件上去。 #include <stdio.h> #define SIZE 4 struct student_type { char name[10]; int num; int age; char addr[15]; }stud[SIZE]; /*定义结构*/ void save( ) { FILE *fp; int i; if((fp=fopen("stu-list","wb"))==NULL) { printf("cannot open file\n"); return; } for(i=0;i<SIZE;i++)/*二进制写*/ if(fwrite(&stud[i],sizeof(struct student_type),1,fp)!=1) printf(“file write error\n”);/*出错处理*/ fclose(fp); } /*关闭文件*/ main() { int i; for(i=0;i<SIZE;i++)/*从键盘读入学生信息*/ scanf("%s%d%d%s",stud[i].name,&stud[i].num,&stud[i].age,stud[i].addr); save( ); }/*调用save()保存学生信息*/
#include <stdio.h> #define SIZE 4 struct student_type { char name[10]; int num; int age; char addr[15]; }stud[SIZE]; main( ) { int i; FILE*fp; fp=fopen("stu-list","rb"); for(i=0;i<SIZE;i++) { fread(&stud[i],sizeof(struct student_type),1,fp); printf("%\-10s %4d %4d %\-15s\n",stud[i].name,stud[i].num,stud[i]. age,stud[i].addr); } fclose (fp); }
如果已有的数据已经以二进制形式存储在一个磁盘文件“stu-dat”中,要求从其中读入数据并输出到“stu-list”文件中,可以编写一个load函数,从磁盘文件中读二进制数据。 void load( ) { FILE *fp;int i; if((fp=fopen("stu-dat","rb"))==NULL) { printf("cannot open infile\n"); return; } for(i=0;i<SIZE;i++) if(fread(&stud[i],sizeof(struct student_type),1,fp)!=1) { if(feof(fp)) {fclose(fp); return;} printf("file read error\n"); } fclose (fp); } 三、格式化读写函数(fprintf()和fscanf()) 函数调用: fprintf ( 文件指针,格式字符串,输出表列); fscanf ( 文件指针,格式字符串,输入表列); 函数功能: 从磁盘文件中读入或输出字符。 例: fprintf(fp,”%d,%6.2f”,i,t); Fscanf (fp,”%d,%f”,&i,&t); 注意: 用fprintf和fscanf函数对磁盘文件读写,使用方便,容易理解,但由于在输入时要将ASCII码转换为二进制形式,在输出时又要将二进制形式转换成字符,花费时间比较多。因此,在内存与磁盘频繁交换数据的情况下,最好不用fprintf和fscanf函数,而用fread和fwrite函数。 四、其他读写函数 putw()和getw() 函数调用: putw(int i,FILE * fp); int i = getw(FILE * fp); 函数功能: 对磁盘文件中读写一个字(整数)。 例: putw(10,fp); i = getw(fp); gutw函数定义如下: gutw(FILE *fp) { char s; s=char *&i; s[0] = getc(fp); s[1] = getc(fp); return i; } 用户自定义读取其他类型数据的函数。 向磁盘文件写一个实数(用二进制方式)的函数putfloat : putfloat(float num,FILE *fp) { char *s; int count; s = (char*)# for(count = 0;count < 4;count++) putc(s[count],fp); } fgets函数 函数作用: 从指定文件读入一个字符串。 函数调用: fgets(str,n,fp); 从fp指向的文件输入n-1个字符,在最后加一个’\0’。 返回值: str的首地址。 fputs函数 函数作用: 向指定的文件输出一个字符串。 函数调用: fgets(“china”,fp); 第一个参数可以是字符串常量、字符数组名或字符型指针。字符串末尾的′\0′不输出。 返回值: 输入成功,返回值为0; 输入失败,返回EOF。 13.5 文件的定位 #include<stdio.h> main() { FILE *fp1,*fp2; fp1=fopen("file1.c","r"); fp2=fopen("file2.c","w"); while(!feof(fp1)) putchar(getc(fp1)); rewind(fp1); while(!feof(fp1)) putc(getc(fp1),fp2); fclose(fp1);fclose(fp2); } 顺序读写和随机读写 顺序读写: 位置指针按字节位置顺序移动。 随机读写: 读写完上一个字符(字节)后,并不一定要读写其后续的字符(字节),而可以读些文件中任意位置上所需要的字符(字节)。 fseek函数(一般用于二进制文件) 函数功能: 改变文件的位置指针。 函数调用形式: fseek(文件类型指针,位移量,起始点) 起始点:文件开头 SEEK_SET 0 文件当前位置 SEEK_CUR 1 文件末尾 SEEK_END 2 位移量:以起始点为基点,向前移动的字节数。一般 要求为long型。 fseek函数应用举例 fseek(fp,100L,0);//将位置指针移到离文件头100个字节处。 fseek(fp,50L, 1);//将位置指针移到离当前位置50个字节处。 fseek(fp,50L, 2);//将位置指针从文件末尾处向后退10个字节。 #include <stdlib.h> #include<stdio.h> struct student_type { char name[10]; int num; int age; char sex; }stud[10]; main() { int i; FILE *fp; if((fp=fopen("stud-dat","rb"))==NULL) { printf("can not open file\n"); exit(0); } for(i=0;i<10;i+=2) { fseek(fp,i*sizeof(struct student_type),0); fread(&stud[i], sizeof(struct student_type),1,fp); printf(“%s %d %d %c\n”,stud[i].name,stud[i].num,stud[i].age,stud[i].sex); } fclose(fp); } ftell函数 函数作用: 得到流式文件中的当前位置,用相对于文件开头的位移量来表示。 返回值: 返回当前位置,出错时返回-1L。 应用举例: i = ftell(fp); if(i==-1L) printf(“error\n”); 13.6 出错的检测 ferror函数 调用形式: ferror(fp); 返回值: 返回0,表示未出错;返回非0,表示出错。 在调用一个输入输出函数后立即检查ferror函数的值,否则信息会丢失。在执行fopen函数时,ferror函数的初始值自动置为0。 clearerr函数 调用形式: clearerr(fp); 函数作用: 使文件错误标志和文件结束标志置为0。 只要出现错误标志,就一直保留,直到对同一文件调用clearerr函数或rewind函数,或任何其他一个输入输出函数。 13.7 文件输入输出小结
|
|
来自: running_to_you > 《第十三章 文件》