




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
§13.1C文件概述
文件(file),狭义的是指存储在外部介质上的数据集合。这表现在:操作系统在从外部存储介质上存/取数据时,都是以文件名作为标识进行的。比如磁盘文件、磁带文件等。
实际上,操作系统对数据的管理都是以文件为单位的,包括:操作系统把数据的输入/输出终端设备也当作文件来处理,例如把键盘作为输入文件,把显示屏和打印机作为输出文件。C语言把所有的外部设备都当作文件来处理,称之为设备文件,从而把实际的物理设备抽象为逻辑文件的概念,把对所有外部设备的输入输出处理变成了对相应设备文件的读写过程。这样,就把对设备文件和磁盘文件的处理方法统一起来了。第十三章文件C语言没有专门的输入输出语句,它对文件的读/写都是通过调用库函数中的输入输出函数来实现的,这些函数既能处理磁盘文件,也能控制外部设备。ANSIC对输入输出函数的标准进行了规定。C语言中的文件是流式文件,即文件是一个字节流或二进制流。这种文件把数据看作是一连串的字符(以字节为单位进行存取),而不是一个个的记录(record),这和Pascal之类的语言是不相同的。这种文件输入输出的数据流的开始和结束只受程序的控制而不受物理符号(如回车换行符)的控制。根据文件中数据的组织形式,C语言的文件可分为:文本文件(ASCII码文件)和二进制文件。1.文本文件
文件中的每一个字节都代表着一个相应的字符,而且存放的就是相应字符的ASCII码值。特点是:可以直接阅读,也可以按字符逐个处理,但占用存储空间较大,同时需要额外的转换时间.即:把内存中的数据写入文件时需按格式将二进制码转换成ASCII码,把文件中的数据读入内存时,也需将ASCII码转换成二进制码.2.二进制文件二进制文件是将数据按其在内存中的实际存放形式直接存入文件中。
特点是:节省存储空间和转换时间,但不能直接阅读。一般用于存放数据或中间结果,当需要时可以直接送入内存,以提高处理速度。例如:有一个整数10002,在内存中占2个字节,如果按ASCII码形式输出到文件中,则要占5个字节,分别是字符‘1’、‘0’、‘0’、‘0’、‘0’、‘2’的ASCII码;而按二进制形式输出到文件中时,则只占2个字节,存放的内容是:0010011100010010。程序数据区输出文件缓冲区输入文件缓冲区磁盘文件2、非缓冲文件系统:
系统并不自动地为正在使用的文件名开辟缓冲区,而是由程序为每个文件设定缓冲区。ANSIC标准决定不采用非缓冲文件系统,而只采用“缓冲文件系统”,它既可处理文本文件,也可处理二进制文件。不同的C语言版本对文件的处理方法是不同的:1、缓冲文件系统:
系统自动在内存区为每一个正在使用的文件名开辟一个大小确定的缓冲区(一般为512字节),数据的输入和输出都要先经过这个缓冲区。在缓冲文件系统中,关键是要掌握“文件指针”的概念。每一个被使用的文件都在内存中开辟了一个区,用来存放文件的相关信息。这些信息保存在一个结构体变量中。该结构体是由系统定义的,取名为FILE。它的含义包含在“stdio.h”文件中:typedefstruct{shortlevel;/*缓冲区“满”或“空”的程度*/unsignedflags;/*文件状态标志*/char_fd;/*文件描述符*/unsignedcharhold;/*如无缓冲区不读取字符*/shortbsize;/*缓冲区的大小*/unsignedchar*baffer;/*数据缓冲区的位置*/unsignedchar*_curp;/*文件位置指针*/unsignedistemp;/*临时文件,指示器*/shorttoken;/*用于有效性检查*/}FILE;
§13.2文件类型指针有了结构体FILE类型(文件结构体类型)以后,我们就可以用它来定义若干个FILE类型的变量,以便存放相应文件的若干信息。但是,对于FILE类型的变量,一般不需要用户自己去定义和直接操作,而是由相应的文件操作函数来实现的。我们只需要做的是:定义FILE类型的指针变量,然后调用对文件进行相应操作的函数。FILE类型指针变量的定义:FILE*fp;其中,fp是一个指向FILE结构体类型的指针变量(简称“文件指针”)。通过fp就能实现对相应文件的操作。§13.3文件的打开与关闭
13.3.1文件的打开(fopen函数)格式:FILE*fp;fp=fopen(文件名,使用方式);其中:
1、“文件名”可以是用双引号括起来的文件名字;也可以是存放文件名字符串的首地址。2、“使用方式”:常见的有“r”,“w”,“rb”,“wb”,“r+”,“w+”等。(详见表13.1P312).
打开文件文件的读或写关闭文件C语言对文件的操作过程:3、正常情况下,fopen函数的返回值是,所打开文件的FILE类型变量的地址(即指向相应文件的指针)。如:FILE*fp;fp=fopen(“f1.c”,“r”);被打开的文件名前面可以指明盘符和路径。如:fp=fopen(“d:\\user\\stu.dat”,“r”);如果不能打开指定文件,则返回一个空指针值NULL。NULL在stdio.h文件中已定义为0。
补充理解:文件打开函数的功能调用文件的打开函数,系统会在内存中为要打开的文件建立相应的FILE类型变量(保存有该文件的所有操作信息),然后将该变量的地址作为函数的返回值,我们将此返回值赋给一个FILE类型的指针变量。通过此指针变量,我们便可以对相应文件进行操作了。fp磁盘文件1磁盘文件2……为要打开的文件建立一个FILE类型的结构体变量*打开文件的常用格式:
FILE*fp;if((fp=fopen(“f1.c”,“r”))==NULL){printf(“Cannotopenthisfile\n”);
exit(0);}其中exit函数的作用是:不管当前在哪个函数调用过程中,一旦执行exit函数,便终止当前程序,返回到操作系统中.说明:1.关于文件的使用方式:(1)“r”方式:用于打开一个已存在的文本文件,只能从该文件中读入数据。打开时,文件位置指针自动指向文件开头。
“w”方式:该方式只能用于向文件中写入数据。要打开的文本文件若已经存在,则打开时先删除该文件,然后重新建立一个新文件;若不存在,则新建一个这样的空文件。
“a”(append)方式:该方式用于向文本文件末尾添加数据.文件打开时,位置指针自动指向文件末尾.如文件不存在,则创建一个新文件.(2)“r+”,“w+”,“a+”方式:均为可读/可写方式,区别是:r+:被打开的文件应存在,否则无法打开文件。打开后位置指针指向文件的开头,如原文件中有内容时,则写入的内容会覆盖原文件内容。
w+:要打开的文件若已存在,则其内容全部丢失,指针指向文件开头;若不存在,则新建一个这样的空文件,指针指向文件的开头。总之,用此方式打开的是一个空文件,“先写后读”。
a+:要打开的文件若已存在,则其内容保留,位置指针自动指向文件末尾;若不存在,则新建一个这样的空文件,指针指向文件的末尾。总之,用此方式打开的文件,位置指针指向文件的末尾,可追加或读取数据,但要注意当前的文件指针位置。(3)另外还有:rb,wb,ab,rb+,wb+,ab+等方式,其含义同前述,只是用于二进制文件而已。
注意:不同的C系统,在文件打开方式的表示上可能不相同,具体随所用的系统而定.2.C语言中有三个标准文件指针由系统分配和控制,即由系统自动打开和关闭,用户不能控制其开闭。
标准输入文件:分配给键盘,文件指针:stdin
标准输出文件:分配给显示器,文件指针:stdout
标准错误输出文件:分配给显示器,文件指针:stderr程序开始运行时,系统自动打开三个标准设备文件。13.3.2文件的关闭(fclose函数)格式:fclose(文件指针);如:fclose(fp);fclose函数也带回一个返回值,正常关闭文件时返回值为0
,否则返回值为EOF(它在stdio.h中被定义为-1,含义为ErrorofFile),这可以用ferror
函数来测试(13.6.1节中讲解)。注意:在对文件操作完毕后,要养成关闭文件的习惯,否则可能会造成数据的丢失。
fclose函数的作用是,若缓冲区中还有输出数据,则先将其输出到磁盘文件,然后释放该文件的FILE类型变量,同时文件指针变量(fp)也就和该文件“脱钩”了。叙述如下:通过调用文件的打开函数,系统会在内存中为要打开的文件建立相应的FILE类型变量,用户从此函数的返回值可以得到该FILE类型变量的地址,由此用户便可以对相应文件进行操作,处理完毕后又通过调用文件的关闭函数来释放该FILE类型变量。即:打开文件读写文件关闭文件C语言对文件的操作过程:13.4.1fputc和fgetc函数(putc和getc函数)1.fputc函数格式:fputc(ch,fp)
其中:ch是要输出的字符(常量或变量);fp是文件指针变量,它是从fopen函数得到的返回值。作用:将一个字符(ch的值)输出到指定文件中(fp所指向的文件,包括stdout和stderr)。如果成功,则返回值就是所输出的字符;如失败,则返回EOF(-1)符号常量。§13.4文件的读写2.fgetc函数
格式:
ch=fgetc(fp);作用:从指定的文件中读入一个字符(对文本文件)或一个字节的数据(对二进制文件),该文件必须是以读或读写方式打开的.
对于文本文件而言,正常请况下fgetc函数返回一个字符并赋给ch。如遇文件结束符,则返回一个文件结束标志EOF(也是-1,但含义为EndofFile)。因为ASCII码为-1的字符不是可输出字符,正常情况下的字符ASCII码值不可能是-1,所以我们可以使用-1来作为文本文件的结束标志。
对于二进制文件而言,由于读入的一个字节的二进制数据的值有可能是1,比如整型数据511(0000000111111111)的低字节,所以此时就不能再用EOF作为文件的结束标志了;而要用feof函数来测试文件是否真正结束。使用格式:feof(fp)
如是文件结束,则函数的返回值为1,否则为0。这种判别方法对二进制文件和文本文件均适用。举例:从磁盘文件(文本文件)f1.dat中顺序读入字符并在屏幕上显示出来。
#include“stdio.h”main(){FILE*fp;charch;if((fp=fopen(“f1.dat”,“r”))==NULL){printf(“Can’topenfile\n”);exit(0);}while((ch=fgetc(fp))!=EOF)putchar(ch);/*等效于fputc(ch,stdout);*/fclose(fp);}以上while结构也可改为:
while(!feof(fp)){ch=fgetc(fp);putchar(ch);}3.fputc和fgetc函数使用举例例13.1从键盘输入一些字符,逐个把它们送到磁盘上去,直到输入一个“#”为止。#include“stdio.h”main(){FILE*fp;charch,filename[10];scanf(“%s”,filename);if((fp=fopen(filename,“w”))==NULL){printf(“Cannotopenthisfile\n”);exit(0);}ch=getchar();while(ch!=‘#’){fputc(ch,fp);putchar(ch);ch=getchar();}fclose(fp);}运行情况:file1.ccomputerandc#
computerandc例13.2将一个磁盘文件中的信息复制到另一个磁盘文件中。#include“stdio.h”main(){FILE*in,*out;
charchinfile[10],outfile[10];printf(“Entertheinfilename:\n”);scanf(“%s”,infile);printf(“Entertheoutfilename:\n”);scanf(“%s”,outfile);if((in=fopen(infile,“r”))==NULL){printf(“Cannotopenthisfile\n”);exit(0);}if((out=fopen(outfile,“w”))==NULL){printf(“Cannotopenthisfile\n”);exit(0);}while(!feof(in))fputc(fgetc(in),out);fclose(in);fclose(out);}此程序也可用于二进制文件的处理,只需将文件的打开方式由“r”和“w”分别改为“rb”和“wb”即可。关于命令行带参数的问题:源程序文件ccopy.c如下#include<stdio.h>main(intargc,char*argv[]){FILE*in,*out;
charch;if(agrc!=3){printf(“ParameterError!\n”);exit(0);}if((in=fopen(argv[1],“r”))==NULL){printf(“Cannotopenthisfile\n”);exit(0);}if((out=fopen(argv[2],“w”))==NULL){printf(“Cannotopenthisfile\n”);exit(0);}while(!feof(in))fputc(fgetc(in),out)
;fclose(in);fclose(out);}得到命令行参数的个数(包括所输入的可执行文件名)此指针数组中依次保存了命令行中每个参数(字符串)的首地址。将以上程序经过编译连接后生成一个可执行文件ccopy.exe,于是我们便可在命令行输入如下内容:
C:\>ccopyfile1.cfile2.c这样,argc的值为3,argv数组中存放的内容为:●●●argv[0]argv[1]argv[2]ccopy\0file1.c\0file2.c\0(演示程序P317.c)最后说明两点:1、在stdio.h中把fputc和fgetc定义为宏名putc和getc,以使书写方便。一般情况下,我们可以把它们作用相同的函数来使用。2、我们在前面曾讲过的putchar和getchar函数实质上就是由fputc和fgetc两个函数派生而来的,在stdio.h头文件中我们可以找到如下的宏定义:
#definegetchar()getc(stdin)#defineputchar(c)putc((c),stdout)13.4.2fread和fwrite函数
格式:
fread(buffer,size,count,fp)fwrite(buffer,size,count,fp)其中,buffer
是一个指针,对fread而言,它是读入数据要存放的起始地址;对fwrite而言,它是要输出数据的起始地址。
size是读/写一次的字节数(数据块的大小)。
count是要读/写的次数(数据块的数量)。
fp文件指针,指向被操作文件(通常是二进制文件)。fread和fwrite函数在正常调用时,其返回值为count的值。作用:用于读写若干个数据块(多个字节)。
例如:floatf[100];……fread(f,4,2,fp);……表示从fp所指向的二进制文件中读入2个实型数据(一个实型数据为4字节)到数组f中。对于保存结构体类型数据的文件,采用块读写函数就更方便了。如:structstudent_type{charname[10];intnum;intage;charaddr[30];}stud[40];……for(i=0;i<40;i++)fread(&stud[i],sizeof(structstudent_type),1,fp1);或:for(i=0;i<40;i++)fwrite(&stud[i],sizeof(structstudent_type),1,fp2);请问:对于以上语句,如果不使用for循环而只用一条语句,如何实现?sizeof称为“长度运算符”,它返回变量或数据类型的字节数,是一个单目运算符。这里返回的是44(个字节)。fread(stud,sizeof(structstudent_type),
40,fp1);例13.3从键盘输入4个学生的有关数据,然后把它们转存到磁盘文件上去.(设文件名为stu_list)#include“stdio.h”#defineSIZE4structstudent_type{charname[10];intnum;intage;charaddr[15];}stud[SIZE];voidsave(){FILE*fp;inti;if((fp=fopen(“stu_list”,“wb”))==NULL){printf(“Cannotopenthisfile\n”);return;}for(i=0;i<SIZE;i++)if(fwrite(&stud[i],sizeof(structstudent_type),1,fp)!=1){printf(“filewriteerror\n”);break;}}29个字节main(){inti;for(i=0;i<SIZE;i++)scanf(“%s%d%d%s”,stud[i].name,&stud[i].num,&stud[i].age,stud[i].addr);
save();}运行时,若输入以下4个学生的姓名,学号,年龄和地址:zhang100119room_101fun100220room_102tan100321room_103ling100419room_104则以上信息将被写入到磁盘文件stu_list中。对于以上的stu_list文件,我们又可用以下程序将其显示出来。#include“stdio.h”#defineSIZE4structstudent_type{charname[10];intnum;intage;charaddr[15];}stud[SIZE];main(){inti;FILE*fp;fp=fopen(“stu_list”,“rb”);for(i=0;i<SIZE;i++)if(fread(&stud[i],sizeof(structstudent_type),1,fp)==1){printf(“%10s%4d%4d%15s\n”,stud[i].name,stud[i].num,stud[i].age,stud[i].addr);}elseif(feof(fp))return;elseprintf(“filereaderror\n”);}此程序的运行结果就是前面所输入的内容。说明:1.在输入输出数据过程中的转换问题:从键盘的输入缓冲区到用户的数据区,如果是字符型数据,不存在转换问题,因为程序对字符的处理就是按其ASCII码来处理的;如果是数值型数据,则要进行相应的二进制转换(如下图)。键盘键盘输入缓冲区(ASCII码)用户程序数据区(二进制)二进制文件ASCII码文件wbw2.fread和fwrite函数一般用于二进制文件的输入和输出。因为它们是按数据块的长度来处理输入输出的,如果用于处理ASCII码文件,就可能出现数据长度和数据格式不匹配的问题。从而产生数据混乱!显示终端若在磁盘文件“stu_dat”中已有4位学生的数据,要求从该文件中读入数据并存放到“stu_list”文件中。则完整的程序为:
#include“stdio.h”#defineSIZE4structstudent_type{charname[10];intnum;intage;charaddr[15];}stud[SIZE];
voidload(){inti;FILE*fp;if((fp=fopen(“stu_dat”,“rb”))==NULL){printf(“Cannotopeninfile\n”);return;}for(i=0;i<SIZE;i++)if(fread(&stud[i],sizeof(structstudent_type),1,fp)!=1){if(feof(fp))return;printf(“filereaderror\n”);}fclose(fp);}voidsave(){FILE*fp;inti;if((fp=fopen(“stu_list”,“wb”))==NULL){printf(“Cannotopenthisfile\n”);return;}for(i=0;i<SIZE;i++)if(fwrite(&stud[i],sizeof(structstudent_type),1,fp)!=1){printf(“filewriteerror\n”);break;}fclose(fp);}main(){load();save();}13.4.3fprintf和fscanf函数
与我们前面所讲的printf和scanf函数的作用相似,都是格式化读写函数。只是后者以终端(键盘,显示器)为读/写对象。而前者是以磁盘文件为读/写对象。调用格式:fprintf(fp,格式字符串,输出表列);
fscanf(fp,格式字符串,输入表列);如:inti=3;floatt=4.5;……fprintf(fp,“%d,%6.2f”,i,t);
则是将字符串
3,4.50
写到fp所指向的磁盘文件中。相应的也有:fscanf(fp,“%d,%f”,&i,&t);
作用:fprintf和fscanf函数用于对ASCII码磁盘文件进行读写,输入时要将ASCII码转换为二进制形式,输出时又要将二进制形式转换为ASCII码形式。因此,这两个函数对磁盘的操作比较费时,不利于内存与磁盘间进行频繁的数据交换。13.4.4其它读写函数1.putw和getw函数
作用:从指定的磁盘文件中读/写一个字(整数)。如:i=getw(fp);putw(10,fp);/*其中10为一个整型常量*/2.fgets和fputs函数作用:从指定的ASCII码磁盘文件中读/写一个字符串。如:charstr[100];fgets(str,n,fp);即从fp指向的文件中读入n1个字符,并放入数组str中,然后在最后加上一个‘\0’字符,共得到n个字符;若在读完(n1)个字符之前遇到了换行符或EOF,则读入立即结束。函数返回值为str的首地址。相应的也有:fputs(“China”,fp);或:fputs(str,fp);即:输出一个字符串到指定的磁盘文件中,不输出结束标志‘\0’。若输出成功,函数返回值为0;若失败返回值为EOF。在FILE结构体类型中,有一个位置指针(curp),指向当前读写文件的位置。通常,在读写一个文件时,文件位置指针是自动变化的,即读写完一个字符后,自动移向下一个字符的位置,这种方式称为“顺序读写”。但是,有时我们又希望打破这种规律,将位置指针按需要随机地指向任意位置,然后进行读写,这种方式称为“随机读写”。对于流式文件,这两种读写方式都是可行的。但要实现随机读写,往往需要调用相关的函数。§13.5文件的定位13.5.1rewind函数格式:
rewind(fp);作用:使文件位置指针重新返回到文件的开头。此函数无返回值。
例13.4(P323)打开一个磁盘文件,先将它的内容显示在屏幕上,然后再把它复制到另一个文件中。
#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);}-1磁盘文件file1.ccurpcurp13.5.2fseek函数
格式:fseek(文件类型指针,位移量,起始点)
作用:根据“起始点”+“位移量”,决定当前位置指针的位置。
说明:1、参数“起始点”可以是0、1或2,含义为:(表13.2)起始点宏名数字文件开始SEEK_SET0文件当前位置SEEK_CUR1文件末尾SEEK_END22、参数“位移量”:是指以起始点为基准点,向前移动的字节数。要求用长整型数据,以使文件大于64k时不会出问题。如:fseek(fp,100L,0);fseek(fp,50L,1);fseek(fp,10L,2);3、fseek函数一般用于二进制文件,对于文本文件,由于存在字符转换的问题,位置计算往往会出现混乱。#include“stdio.h”structstudent_type{charname[10];intnum;intage;charsex;/*共占15个字节*/}stud[10];main(){inti;FILE*fp;if((fp=fopen(“stud.dat”,“rb”))==NULL){printf(“Cannotopeninfile\n”);exit(0);}例13.5在磁盘文件stud.dat上存有10个学生的数据,要求读入第1,3,5,7,9个学生的数据,然后在屏幕上显示出来。for(i=0;i<10;i+=2){fseek(fp,i*sizeof(structstudent_type)
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 纸容器生产过程中的能源回收利用考核试卷
- 2025年中国变电监测行业市场前景预测及投资价值评估分析报告
- 2025年中国备份系统行业市场前景预测及投资价值评估分析报告
- 2025年中国北京市5G行业市场前景预测及投资价值评估分析报告
- 艺术品鉴定与投资咨询服务合同
- 智能门锁系统安装与终身保养服务协议
- 2025年中国钣金工程安装行业市场前景预测及投资价值评估分析报告
- 电池检测设备租赁、维修及升级服务合同
- 葡萄酒品牌形象代言人推广补充合同
- 景观园林景观设计与施工监理合同
- 《测绘管理法律与法规》课件-测绘成果管理
- 事业部机构设置
- 高速铁路站场围墙施工方案
- 2024版国开电大专科《现代教育思想》在线形考(形考任务一至二)+终结性考试试题
- 沉香项目市场营销方案
- 办公楼用电改造施工方案
- 安全风险四色分布图图例
- 物理才是最好的人生指南
- 软件系统操作手册模板
- 物流专线合作协议书
- 华兴报告生物育种:前沿生物技术改造下的新农业
评论
0/150
提交评论