版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
會(huì)計(jì)學(xué)1第文件C語(yǔ)言程序設(shè)計(jì)第三電子11.1文件概述【問題】數(shù)據(jù)在計(jì)算機(jī)中如何被保存和閱讀?11.1.1文件的概念所謂“文件”是指一組相關(guān)數(shù)據(jù)的有序集合。這個(gè)數(shù)據(jù)集有一個(gè)名稱,叫做文件名。例如:k:\24000101\program.c,其中k:\24000101就是路徑,program.c是文件名。當(dāng)需要使用文件的時(shí)候,需要將文件調(diào)入內(nèi)存中。第1頁(yè)/共72頁(yè)11.1.2文件的分類從用戶使用的角度看,文件可分為普通文件和設(shè)備文件從文件編碼和數(shù)據(jù)的組織方式來看,文件可分為ASCII碼文件和二進(jìn)制碼文件。ASCII文件也稱為文本文件,文件在磁盤中存放時(shí)每個(gè)字符占一個(gè)字節(jié),每個(gè)字節(jié)中存放相應(yīng)字符的ASCII碼。內(nèi)存中的數(shù)據(jù)存儲(chǔ)時(shí)需要轉(zhuǎn)換為ASCII碼。二進(jìn)制文件則不同,內(nèi)存中的數(shù)據(jù)存儲(chǔ)的時(shí)候不需要進(jìn)行數(shù)據(jù)轉(zhuǎn)換,存儲(chǔ)介質(zhì)上保存的數(shù)據(jù)采用與內(nèi)存數(shù)據(jù)一致的表示形式存儲(chǔ)。第2頁(yè)/共72頁(yè)11.1.2文件的分類從C語(yǔ)言對(duì)文件的處理方法來看。舊的C版本(如Unix系統(tǒng)下使用的C)有兩種對(duì)文件的處理方法:一種叫“緩沖文件系統(tǒng)”,一種叫“非緩沖文件系統(tǒng)”。緩沖文件系統(tǒng):系統(tǒng)自動(dòng)地在內(nèi)存區(qū)為每一個(gè)正在使用的文件名開辟一個(gè)緩沖區(qū)。從內(nèi)存向磁盤輸出數(shù)據(jù)必須先送到內(nèi)存中的緩沖區(qū),裝滿緩沖區(qū)后才一起送到磁盤去。非緩沖文件系統(tǒng):指系統(tǒng)不自動(dòng)開辟確定大小的緩沖區(qū),而由程序?yàn)槊總€(gè)文件設(shè)定緩沖區(qū)。第3頁(yè)/共72頁(yè)11.2文件操作11.2.1FILE文件類型指針
typedefstruct{shortlevel;/*緩沖區(qū)“滿”或“空”的程度*/unsignedflags;/*文件狀態(tài)標(biāo)志*/charfd;/*文件描述符*/unsignedcharhold;/*無緩沖區(qū)不讀取字符*/shortbsize;/*緩沖區(qū)大小*/unsignedchar*buffer;/*數(shù)據(jù)緩沖區(qū)位置指針*/unsignedchar*curp;/*當(dāng)前指針指向*/unsignedistemp;/*臨時(shí)文件指示器*/shorttoken;/*用于有效性檢查*/}FILE;
有了FILE類型以后可以定義文件類型指針變量。例如:
FILE*fp;第4頁(yè)/共72頁(yè)標(biāo)準(zhǔn)設(shè)備文件C語(yǔ)言中的是由系統(tǒng)控制的,由系統(tǒng)自動(dòng)打開和關(guān)閉,其文件結(jié)構(gòu)指針由系統(tǒng)命名,用戶無需說明即可直接使用,例如:stdin
標(biāo)準(zhǔn)輸入文件(鍵盤)stdout
標(biāo)準(zhǔn)輸出文件(顯示器)stderr
標(biāo)準(zhǔn)錯(cuò)誤輸出文件(顯示器)第5頁(yè)/共72頁(yè)11.2.2文件的打開操作C語(yǔ)言用fopen()函數(shù)來實(shí)現(xiàn)文件的打開。fopen函數(shù)的調(diào)用方式一般為:FILE*fp;fp=fopen(文件名,文件使用方式);例如:fp=fopen("result.txt","r");第6頁(yè)/共72頁(yè)11.2.2文件的打開操作打開文件方式文件使用方式含義"r"只讀,文本以只讀方式打開一個(gè)已有的文本文件。"w"只寫,文本以只寫方式建立一個(gè)新的文本文件。如果該文件已存在則將它刪去,然后重新建立一個(gè)新文件。"a"追加,文本以添加方式打開一個(gè)文本文件,在文件末尾添加。如果該文件不存在,則建立一個(gè)新文件后再添加。"rb"只讀,二進(jìn)制以只讀方式打開一個(gè)已有的二進(jìn)制文件。"wb"只寫,二進(jìn)制以只寫方式打開一個(gè)二進(jìn)制文件。"ab"追加,二進(jìn)制以添加方式打開一個(gè)二進(jìn)制文件。第7頁(yè)/共72頁(yè)11.2.2文件的打開操作文件使用方式含義"r+"讀寫,文本以讀寫方式打開一個(gè)已有的文本文件。"w+"讀寫,文本以讀寫方式建立一個(gè)新的文本文件。"a+"讀寫,文本以讀寫方式打開一個(gè)文本文件,在文件末尾添加和修改,如果文件不存在,則建立一個(gè)新文件后再添加和修改。"rb+"讀寫,二進(jìn)制以讀寫方式打開一個(gè)已有的二進(jìn)制文件。"wb+"讀寫,二進(jìn)制以讀寫方式建立一個(gè)新的二進(jìn)制文件。"ab+"讀寫,二進(jìn)制以讀寫方式打開一個(gè)二進(jìn)制文件。打開文件方式第8頁(yè)/共72頁(yè)說明用以上方式可以打開文本文件或二進(jìn)制文件,這是ANSIC的規(guī)定,即用同一種緩沖文件系統(tǒng)來處理文本文件和二進(jìn)制文件。但目前使用的有些C編譯系統(tǒng)可能不完全提供所有這些功能(例如有的只能用“r”、“w”、“a”方式),有的C版本不用“r+”、“w+”、“a+”而用“rw”、“wr”、“ar”等,請(qǐng)讀者注意所用系統(tǒng)的規(guī)定。第9頁(yè)/共72頁(yè)說明如果不能實(shí)現(xiàn)“打開”的任務(wù),fopen函數(shù)將會(huì)返回一個(gè)出錯(cuò)信息。出錯(cuò)的原因可能是:用“r”方式打開一個(gè)并不存在的文件;磁盤出故障;磁盤已滿無法建立新文件等。此時(shí)fopen函數(shù)將帶回一個(gè)空指針值NULL(NULL在stdio.h文件中已被定義為0)。常用下面的方法打開一個(gè)文件:if((fp=fopen("filename","r“))==NULL)
{
printf("cannotopenthisfile.\n“);
exit(0);
}第10頁(yè)/共72頁(yè)說明用“w”方式打開文件時(shí),只能從內(nèi)存向該文件輸出(寫)數(shù)據(jù),而不能從文件向內(nèi)存輸入數(shù)據(jù)。如果該文件原來不存在,則打開時(shí)按指定文件名建立一個(gè)新文件。如果原來的文件已經(jīng)存在,則打開時(shí)將文件刪空,然后重新建立一個(gè)新文件,所以務(wù)必小心。第11頁(yè)/共72頁(yè)說明用“a”方式打開文件時(shí),向文件的尾部添加新數(shù)據(jù),文件中原來的數(shù)據(jù)保留,但要求文件必須存在,否則會(huì)返回出錯(cuò)信息。打開文件時(shí),文件的位置指針在文件末尾。用“r+”、“w+”、“a+”方式打開文件時(shí),既可以輸入也可以輸出,不過三種方式是有區(qū)別的:“r+”方式要求必須文件存在;“w+”方式則建立新文件后進(jìn)行讀寫;“a+”方式則保留文件原有的數(shù)據(jù),進(jìn)行追加或讀的操作。第12頁(yè)/共72頁(yè)說明在用文本文件向計(jì)算機(jī)輸入時(shí),應(yīng)將回車和換行兩個(gè)字符轉(zhuǎn)換為一個(gè)換行符;在輸出時(shí),應(yīng)將換行符轉(zhuǎn)換為回車和換行兩個(gè)字符。在用二進(jìn)制文件時(shí),不需進(jìn)行這種轉(zhuǎn)換,因?yàn)樵趦?nèi)存中的數(shù)據(jù)形式與輸出到外部文件中的數(shù)據(jù)形式完全一致,一一對(duì)應(yīng)。第13頁(yè)/共72頁(yè)說明在程序開始運(yùn)行時(shí),系統(tǒng)自動(dòng)打開三個(gè)標(biāo)準(zhǔn)文件:標(biāo)準(zhǔn)輸入、標(biāo)準(zhǔn)輸出、標(biāo)準(zhǔn)出錯(cuò)輸出。通常這三個(gè)文件都與終端相聯(lián)系。因此以前我們所用到的從終端輸入或輸出,都不需要打開終端文件。系統(tǒng)自動(dòng)定義了三個(gè)文件指針stdin、stdout和stderr,分別指向終端輸入、終端輸出和標(biāo)準(zhǔn)出錯(cuò)輸出(也從終端輸出)。如果程序中指定要從stdin所指的文件輸入數(shù)據(jù),就是指從終端鍵盤輸入數(shù)據(jù)。第14頁(yè)/共72頁(yè)11.2.3文件的關(guān)閉操作文件在使用完后應(yīng)該及時(shí)關(guān)閉它,以防止它再被誤用?!瓣P(guān)閉”就是釋放文件指針。釋放后的文件指針變量不再指向該文件,為自由的文件指針。這種方式可以避免文件中的數(shù)據(jù)丟失。釋放指針后不能再通過該指針對(duì)原對(duì)應(yīng)的文件進(jìn)行讀寫操作,除非再次用該指針變量打開該文件。用fclose函數(shù)關(guān)閉文件。fclose函數(shù)調(diào)用的一般形式為:fclose(文件指針);例如:fclose(fp);如果文件關(guān)閉成功,fclose函數(shù)返回值為0;如果關(guān)閉出錯(cuò),則返回值為EOF(-1)。這可以用ferror函數(shù)來測(cè)試。第15頁(yè)/共72頁(yè)11.2.4文件的讀寫操作字符讀寫函數(shù)字符輸入函數(shù)fgetc從指定文件讀入一個(gè)字符,該文件必須是以讀或讀寫方式打開的。fgetc函數(shù)的調(diào)用形式為:ch=fgetc(fp);第16頁(yè)/共72頁(yè)【例11-1】顯示文本文件readme.txt的內(nèi)容。
#include<stdio.h>voidmain(){FILE*fp; charch;if((fp=fopen("readme.txt","r"))==NULL) { printf("fileopenerror.\n"); exit(0); }while((ch=fgetc(fp))!=EOF)putchar(ch);fclose(fp);}該程序完成:從一文件名為“readme.txt”的磁盤文件中順序讀取字符,并在標(biāo)準(zhǔn)輸出設(shè)備顯示器上輸出。第17頁(yè)/共72頁(yè)注意EOF為文本文件的結(jié)束標(biāo)志。二進(jìn)制文件中的數(shù)據(jù),某一個(gè)字節(jié)的值可能是-1,而這又恰好是EOF的值。所以,上述程序只適合處理文本文件。ANSIC已允許用緩沖區(qū)文件系統(tǒng)處理二進(jìn)制文件.為了解決上述問題,ANSIC提供了一個(gè)feof函數(shù)來判斷文件是否真的結(jié)束。feof(fp)用來測(cè)試fp所指向的文件當(dāng)前狀態(tài)是否為“文件結(jié)束”。如果是文件結(jié)束,函數(shù)feof(fp)的值為1(真),否則為0(假)。
第18頁(yè)/共72頁(yè)注意如果想順序讀取一個(gè)二進(jìn)制文件的數(shù)據(jù),上面的程序修改為:ch=fgetc(fp);while(!feof(fp))/*相當(dāng)于while(feof(fp)==0)*/{putchar(ch);ch=fgetc(fp);}
第19頁(yè)/共72頁(yè)字符輸出函數(shù)fputcfputc函數(shù)把一個(gè)字符輸出到磁盤文件上。其一般形式為:fputc(ch,fp);【說明】ch是要輸出的字符,它可以是一個(gè)字符常量,也可以是一個(gè)字符變量。第20頁(yè)/共72頁(yè)【例11-2】從鍵盤上輸入的字符代碼順序存入名為“result.txt”的磁盤文件中,當(dāng)鍵盤輸入Ctrl+Z時(shí)關(guān)閉文件,輸入結(jié)束。
#include"stdio.h"voidmain(){FILE*fp; intch;
if((fp=fopen("result.txt","w"))==NULL){printf("filecreatederror.\n");exit(0);}do{ch=getchar();/*注意次序,先輸入字符再寫到文件中*/fputc(ch,fp);}while(ch!=EOF);fclose(fp);}第21頁(yè)/共72頁(yè)【例11-3】編程完成將文本文件readme.txt復(fù)制到result.txt中。while((ch=fgetc(fp1))!=EOF)
fputc(ch,fp2);
fclose(fp1);
fclose(fp2);
}#include<stdio.h>
main()
{
FILE*fp1,*fp2;
charch;
if((fp1=fopen("readme.txt","r"))==NULL)
{
printf("file1opennederror.\n");
exit(0);
}
if((fp2=fopen("result.txt","w"))==NULL)
{
printf("file2createderror.\n");
exit(0);
}第22頁(yè)/共72頁(yè)字符串讀寫函數(shù)讀文件字符串函數(shù)fgets從指定文件讀入一個(gè)字符串,該文件必須是以讀或讀寫方式打開的。fgets函數(shù)的調(diào)用形式為:fgets(str,n,fp);【說明】參數(shù)str可以是一個(gè)字符型數(shù)組名或指向字符串的指針;參數(shù)n為讀取的最多的字符個(gè)數(shù);參數(shù)fp為要讀取文件的指針。第23頁(yè)/共72頁(yè)字符串讀寫函數(shù)-fgets【功能】從fp指定的文件中讀取長(zhǎng)度不超過n-1個(gè)字符的字符串,并將該字符串放到字符數(shù)組str中。讀取成功,函數(shù)返回字符數(shù)組str的首地址;如果文件結(jié)束或出錯(cuò),則返回NULL。讀取操作遇到以下情況結(jié)束:①已經(jīng)讀取了n-1個(gè)字符;②當(dāng)前讀取到的字符為回車符;③已讀取到文件末尾。第24頁(yè)/共72頁(yè)注意使用該函數(shù)時(shí),從文件讀取的字符個(gè)數(shù)不會(huì)超過n-1個(gè),這是由于在字符串尾部還需自動(dòng)追加一個(gè)“\0”字符,這樣讀取到的字符串在內(nèi)存緩沖區(qū)正好占有n個(gè)字節(jié)。如果從文件中讀取到回車符時(shí),也作為一個(gè)字符送入由str所指的內(nèi)存緩沖區(qū),然后再向緩沖區(qū)送入一個(gè)“\0”字符。應(yīng)注意,fgets()函數(shù)在使用stdin作為fp參數(shù)時(shí)與gets()函數(shù)功能有所不同:gets()把讀取到的回車符轉(zhuǎn)換成“\0”字符,而fgets()把讀取到的回車符作為字符存儲(chǔ),然后再在末尾追加“\0”字符。第25頁(yè)/共72頁(yè)注意假設(shè)文件readme.txt的內(nèi)容如下:有數(shù)組charstr[8];,文件指針fp指向readme.txt,讀寫位置指向字符c。運(yùn)行語(yǔ)句fgets(str,8,fp);后str的內(nèi)容為:再次運(yùn)行fgets(str,8,fp);后str的內(nèi)容為:第3次運(yùn)行fgets(str,8,fp);后str的內(nèi)容為:第26頁(yè)/共72頁(yè)字符串輸出函數(shù)fputsfputs函數(shù)把一個(gè)字符串輸出到磁盤文件上。其一般形式為:
fputs(str,fp);【說明】str可以是指向字符串的指針或字符數(shù)組名,也可以是字符串常量;fp為指向?qū)懭胛募闹羔??!竟δ堋繉⒂蓅tr指定的字符串寫入fp所指向的文件中。第27頁(yè)/共72頁(yè)注意與fgets()函數(shù)在輸入字符串時(shí)末尾自動(dòng)追加“\0”字符的特性相對(duì)應(yīng),fputs()函數(shù)在將字符串寫入文件時(shí),其末尾的“\0”字符自動(dòng)舍去。當(dāng)fputs()函數(shù)使用stdout作為fp參數(shù)時(shí),即fputs(str,stdout)與puts(str)在功能上有所不同:fputs()舍棄輸出字符串末尾加入的“\0”字符,而puts()把它轉(zhuǎn)換成回車符輸出。正常操作時(shí),返回值為寫入的字符個(gè)數(shù);出錯(cuò)時(shí),返回值為EOF(-1)。第28頁(yè)/共72頁(yè)【例11-4】將鍵盤輸入的若干行字符存入到磁盤文件result.txt中#include<stdio.h>voidmain(){FILE*fp; charstr[101];if((fp=fopen("result.txt","w"))==NULL){printf("filecreatederror.\n"); exit(0); }while(strlen(gets(str))>0)/*讀取字符串,輸入空串時(shí)結(jié)束*/{fputs(str,fp);/*寫到文件fp中*/ fputs("\n",fp);}fclose(fp);}第29頁(yè)/共72頁(yè)【例11-5】編程完成將文本文件readme.txt復(fù)制到result.txt中。#include<stdio.h>voidmain(){FILE*fp1,*fp2; charstr[20];if((fp1=fopen("readme.txt","r"))==NULL){printf("file1opennederror.\n"); exit(0); }if((fp2=fopen("result.txt","w"))==NULL){printf("file2createderror.\n"); exit(0);}while(fgets(str,20,fp1)!=NULL)fputs(str,fp2);fclose(fp1);fclose(fp2);}第30頁(yè)/共72頁(yè)數(shù)據(jù)塊讀寫函數(shù)文件數(shù)據(jù)塊讀函數(shù)freadfread函數(shù)用來從指定文件中讀取一個(gè)指定字節(jié)的數(shù)據(jù)塊。它的一般調(diào)用形式為fread(buffer,size,count,fp);【說明】buffer為讀入數(shù)據(jù)在內(nèi)存中存放的起始地址;size為每次要讀取的字符數(shù);count為要讀取的次數(shù);fp為文件類型指針?!竟δ堋吭趂p指定的文件中讀取count次數(shù)據(jù)項(xiàng)(每次size個(gè)字節(jié))存放到以buffer所指的內(nèi)存單元地址中。第31頁(yè)/共72頁(yè)數(shù)據(jù)塊讀寫函數(shù)文件數(shù)據(jù)塊寫函數(shù)fwritefwrite函數(shù)用來將數(shù)據(jù)輸出到磁盤文件上。它的一般調(diào)用形式為fwrite(buffer,size,count,fp);【說明】buffer為輸出數(shù)據(jù)在內(nèi)存中存放的首地址;size為每次要輸出到文件中的字節(jié)數(shù);count為要輸出的次數(shù);fp為文件類型指針。【功能】將從buffer為首地址的內(nèi)存中取出count次數(shù)據(jù)項(xiàng)(每次size個(gè)字節(jié))寫入fp所指的磁盤文件中第32頁(yè)/共72頁(yè)注意當(dāng)文件以二進(jìn)制形式打開時(shí),fread函數(shù)就可以讀取任何類型的信息。例如:fread(array,4,5,fp);其中,array為一個(gè)實(shí)型數(shù)組名,一個(gè)實(shí)型量占4個(gè)字節(jié)。該函數(shù)從fp所指的數(shù)據(jù)文件中讀取5次4字節(jié)的實(shí)型數(shù)據(jù),存儲(chǔ)到數(shù)組array中。fread()函數(shù)讀取的數(shù)據(jù)塊的總字節(jié)數(shù)應(yīng)該是size*count個(gè)字節(jié)。正常操作時(shí)函數(shù)的返回值為讀取的項(xiàng)數(shù),出錯(cuò)時(shí)為-1。第33頁(yè)/共72頁(yè)注意當(dāng)文件以二進(jìn)制形式打開時(shí),fwrite函數(shù)就可以寫入任何類型的信息。例如:fwrite(array,2,10,fp);其中,array為一個(gè)整型數(shù)組名,一個(gè)整型量占兩個(gè)字節(jié)。該函數(shù)將整型數(shù)組中10個(gè)兩字節(jié)的整型數(shù)據(jù)寫入由fp所指的磁盤文件中。與fread()函數(shù)一樣寫入的數(shù)據(jù)塊的總字節(jié)是size*count個(gè)字節(jié)。正常操作時(shí)返回值為寫入的項(xiàng)數(shù),出錯(cuò)時(shí)返回值為-1。第34頁(yè)/共72頁(yè)【例11-6】編程從鍵盤輸入3個(gè)學(xué)生的數(shù)據(jù),將它們存入到文件result.dat中,然后再讀出顯示在屏幕上。#include<stdio.h>#dedefineSIZE3structstudent{intno;charname[10];intage;charaddress[20];}stud[SIZE],fout;voidstudent_save(){inti;FILE*fp;if((fp=fopen("result.dat","wb"))==NULL) {printf("filecreatederror.\n");return;}for(i=0;i<SIZE;i++)/*寫學(xué)生的信息*/{if(fwrite(&stud[i],sizeof(structstudent),1,fp)!=1)printf("filewriteerror.\n");}fclose(fp);}第35頁(yè)/共72頁(yè)【例11-6】編程從鍵盤輸入3個(gè)學(xué)生的數(shù)據(jù),將它們存入到文件result.dat中,然后再讀出顯示在屏幕上。voidstudent_display(){FILE*fp; inti;if((fout=fopen("result.dat","rb"))==NULL{printf("fileopennederror.\n");return;}printf("No.NameAgeAddress\n");while(fread(&fout,sizeof(fout),1,fp))printf("%4d%-10s%4d%-20s",fout.no,,fout.age,fout.address);fclose(fp);}第36頁(yè)/共72頁(yè)【例11-6】編程從鍵盤輸入3個(gè)學(xué)生的數(shù)據(jù),將它們存入到文件result.dat中,然后再讀出顯示在屏幕上。voidmain(){inti;for(i=0;i<SIZE;i++)/*從鍵盤讀入學(xué)生的信息(結(jié)構(gòu))*/{printf("Pleaseinputstudent%d:",i+1);scanf("%d%s%d%s",&stud[i].no,stud[i].name,&stud[i].age,stud[i].address);}student_save();student_display();}
第37頁(yè)/共72頁(yè)格式化輸入輸出函數(shù)fprintf函數(shù)和fscanf函數(shù)格式化輸入函數(shù)fscanf函數(shù)調(diào)用的格式為fscanf(fp,格式控制串,輸入列表);【說明】fp是指向要讀取文件的文件型指針,格式控制串,輸出列表同scanf函數(shù)?!竟δ堋繌膄p指向的文件中,按格式控制串中的控制符讀取相應(yīng)數(shù)據(jù)賦給輸入列表中對(duì)應(yīng)的變量地址中。第38頁(yè)/共72頁(yè)格式化輸入輸出函數(shù)fprintf函數(shù)和fscanf函數(shù)格式化輸出函數(shù)fprintf函數(shù)調(diào)用的格式為
fprintf(fp,格式控制串,輸出列表);【說明】fp是指向要寫入文件的文件型指針,格式控制串,輸出列表同printf函數(shù)。【功能】將輸出列表中的各個(gè)變量或常量,依次按格式控制串中的控制符說明的格式寫入fp指向的文件中。第39頁(yè)/共72頁(yè)說明用fprintf和fscanf函數(shù)對(duì)磁盤文件讀寫,使用方便,容易理解,但由于在輸入輸出時(shí)要進(jìn)行ASCII碼和二進(jìn)制的轉(zhuǎn)換,時(shí)間開銷大,因此,在內(nèi)存與磁盤頻繁交換數(shù)據(jù)的情況下,最好不用fprintf和fscanf函數(shù),而用fread和fwrite函數(shù)。第40頁(yè)/共72頁(yè)其他讀寫函數(shù)(字)整數(shù)輸入輸出函數(shù)getw和putwputw和getw用來對(duì)磁盤文件讀寫一個(gè)字(整數(shù))。例如:putw(100,fp);它的作用是將整數(shù)100輸出到fp所指的文件,而i=getw(fp);作用是從磁盤文件中讀一個(gè)整數(shù)到內(nèi)存,賦給整型變量i。讀寫其他類型數(shù)據(jù)對(duì)于系統(tǒng)沒有提供函數(shù)的和不能方便完成的讀寫操作,用戶可以自定義讀寫函數(shù),這樣的函數(shù)具有很好的針對(duì)性。第41頁(yè)/共72頁(yè)11.3文件的定位11.3.1置文件位置指針于文件開頭位置的函數(shù)
rewind()rewind()函數(shù)的一般調(diào)用形式為:rewind(fp);【說明】fp是指向由fopen函數(shù)打開的文件指針【功能】使位置指針重新返回文件的開頭,此函數(shù)沒有返回值。第42頁(yè)/共72頁(yè)【例11-7】有一磁盤文件readme.txt,首先將其內(nèi)容顯示在屏幕上,然后把它復(fù)制到另一文件result.txt上。
#include"stdio.h"voidmain(){FILE*fp1,*fp2;if((fp1=fopen("readme.txt","r"))==NULL){printf("fileopennederror.\n");exit(0);}if((fp2=fopen("result.txt","w"))==NULL){printf("filecreatederror.\n");exit(0);}while(!feof(fp1))putchar(fgetc(fp1));rewind(fp1);/*重置文件位置指針至文件頭*/while(!feof(fp1)) fputc(fgetc(fp1),fp2);fclose(fp1);fclose(fp2);}第43頁(yè)/共72頁(yè)11.3.2改變文件位置指針位置的函數(shù)fseekfseek函數(shù)的調(diào)用形式為:fseek(fp,offset,whence);【說明】fp為指向當(dāng)前文件的指針;offset為文件位置指針的位移量,指以起始位置為基準(zhǔn)值向前移動(dòng)的字節(jié)數(shù),要求offset為long型數(shù)據(jù);whence為起始位置,用整型常量表示,ANSIC規(guī)定它必須是0、1或2之一值,它們表示三個(gè)符號(hào)常數(shù),在stdio.h中定義如下:名字值起始位置SEEK_SET0文件開頭SEEK_CUR1文件當(dāng)前位置SEEK_END2文件末尾第44頁(yè)/共72頁(yè)11.3.2改變文件位置指針位置的函數(shù)fseek【功能】將文件位置指針移到由起始位置(whence)開始、位移量為offset的字節(jié)處。如果函數(shù)讀寫指針移動(dòng)失敗,返回值為-1。fseek函數(shù)一般用于二進(jìn)制文件,因?yàn)槲谋疚募l(fā)生字符轉(zhuǎn)換,計(jì)算位置時(shí)往往會(huì)發(fā)生混亂。下面是fseek函數(shù)調(diào)用的幾個(gè)例子:fseek(fp,100L,0);/*將位置指針移到離文件頭100個(gè)字節(jié)處*/fseek(fp,50L,1);/*將位置指針移到離當(dāng)前位置50個(gè)字節(jié)處*/fseek(fp,-20L,2);/*將位置指針從文件末尾處向后退20個(gè)字節(jié)*/注意偏移量為長(zhǎng)整型,如100L。利用fseek函數(shù)就可以實(shí)現(xiàn)隨機(jī)讀寫。第45頁(yè)/共72頁(yè)11.3.3取得文件當(dāng)前位置的函數(shù)ftell
ftell函數(shù)的作用是得到流式文件中的當(dāng)前位置,用相對(duì)于文件開頭的位移量來表示。由于文件中的位置指針經(jīng)常移動(dòng),人們往往不容易辨清其當(dāng)前位置。用ftell函數(shù)可以得到當(dāng)前位置。如果ftell函數(shù)返回值為-1L,則表示出錯(cuò)。例如:if(ftell(fp)==-1L)printf("error\n");第46頁(yè)/共72頁(yè)11.3.4文件的錯(cuò)誤檢測(cè)文件讀寫錯(cuò)誤檢測(cè)函數(shù)在調(diào)用各種輸入輸出函數(shù)(如fputc、fgetc、fread、fwrite等)時(shí),如果出現(xiàn)錯(cuò)誤,則除了函數(shù)返回值有所反映外,還可以用ferror函數(shù)檢查,它的一般調(diào)用形式為:ferror(fp);如果ferror返回值為0(假),則表示未出錯(cuò)。如果返回一個(gè)非0值,則表示出錯(cuò)。應(yīng)該注意,對(duì)同一個(gè)文件,每一次調(diào)用輸入輸出函數(shù),均產(chǎn)生一個(gè)新的ferror函數(shù)值,因此,應(yīng)當(dāng)在調(diào)用一個(gè)輸入輸出函數(shù)后立即檢查ferror函數(shù)的值,否則信息會(huì)丟失。在執(zhí)行fopen函數(shù)時(shí),ferror函數(shù)的初始值自動(dòng)置為0。第47頁(yè)/共72頁(yè)11.3.4文件的錯(cuò)誤檢測(cè)清除文件錯(cuò)誤標(biāo)志函數(shù)clearerr函數(shù)的作用是使文件錯(cuò)誤標(biāo)志和文件結(jié)束標(biāo)志置為0。假設(shè)在調(diào)用一個(gè)輸入輸出函數(shù)時(shí)出現(xiàn)錯(cuò)誤,ferror函數(shù)值為一個(gè)非0值。在調(diào)用clearerr(fp)后,ferror(fp)的值變成0。只要出現(xiàn)錯(cuò)誤標(biāo)志,就一直保留,直到對(duì)同一文件調(diào)用clearerr函數(shù)或rewind函數(shù),或任何其他一個(gè)輸入輸出函數(shù)。第48頁(yè)/共72頁(yè)11.4編譯預(yù)處理編譯預(yù)處理是指在進(jìn)行編譯的第一遍掃描(詞法掃描和語(yǔ)法分析)之前所作的工作。預(yù)處理是C語(yǔ)言的一個(gè)重要功能,它由預(yù)處理程序負(fù)責(zé)完成。當(dāng)對(duì)一個(gè)源文件進(jìn)行編譯時(shí),系統(tǒng)將自動(dòng)引用預(yù)處理程序?qū)υ闯绦蛑械念A(yù)處理部分作處理,處理完畢自動(dòng)進(jìn)入對(duì)源程序的編譯,過程如下圖:第49頁(yè)/共72頁(yè)11.4編譯預(yù)處理C語(yǔ)言提供了多種預(yù)處理功能,如宏定義、文件包含、條件編譯等。合理地使用預(yù)處理功能編寫的程序便于閱讀、修改、移植和調(diào)試,也有利于模塊化程序設(shè)計(jì)。預(yù)處理的命令有以下幾個(gè)特點(diǎn):預(yù)處理命令均以#開頭,結(jié)尾不加分號(hào);預(yù)處理命令可以放在程序中任何位置,作用范圍從定義處到文件結(jié)尾。本章介紹常用的幾種預(yù)處理功能。第50頁(yè)/共72頁(yè)11.4.1宏定義宏提供了用一個(gè)標(biāo)識(shí)符來表示一個(gè)字符串的機(jī)制,實(shí)際上就是一種替換,有時(shí)稱為宏替換。在編譯預(yù)處理時(shí),對(duì)程序中所有出現(xiàn)的“宏”,都用宏定義中的字符串去代換。宏定義由宏定義命令完成,宏代換是由預(yù)處理程序自動(dòng)完成的。宏分為有參數(shù)和無參數(shù)兩種。無參宏定義無參宏的宏名后不帶參數(shù)。其定義的一般形式為:
#define
標(biāo)識(shí)符字符串【說明】define為宏定義命令,標(biāo)識(shí)符為所定義的宏名,字符串可以是常數(shù)、表達(dá)式、格式串等。第51頁(yè)/共72頁(yè)【例11-8】計(jì)算圓的面積和周長(zhǎng)。#include<stdio.h>#definePI3.14159voidmain(){floats,l,r;printf("inputr:");scanf("%f",&r);s=PI*r*r;l=2*PI*r;printf("s=%f,l=%f\n",s,l);}第52頁(yè)/共72頁(yè)注意宏定義是用宏名來表示一個(gè)字符串,在宏展開時(shí)又以該字符串取代宏名,這只是一種簡(jiǎn)單的代換,字符串中可以含任何字符,可以是常數(shù),也可以是表達(dá)式,預(yù)處理程序?qū)λ蛔魅魏螜z查。如有錯(cuò)誤,只能在編譯已被宏展開后的源程序時(shí)發(fā)現(xiàn)。宏定義不是說明或語(yǔ)句,在行末不必加分號(hào),如果加上分號(hào)則連分號(hào)也一起置換。第53頁(yè)/共72頁(yè)注意宏定義必須寫在函數(shù)之外,其作用域?yàn)楹甓x命令起到源程序結(jié)束。如要終止其作用域可使用#undef命令,例如:#definePI3.14159voidmain(){①}#undefPI②PI只在①中有效,在②中無效。第54頁(yè)/共72頁(yè)注意宏名在源程序中若用引號(hào)括起來,則預(yù)處理程序不對(duì)其作宏代換。#definePI3.14159voidmain(){printf("PI");…}程序的運(yùn)行結(jié)果為:PI,而不是3.14159。宏定義允許嵌套。在宏展開時(shí)由預(yù)處理程序?qū)訉哟鷵Q。例如:#definePI3.14159#defineSPI*y*y/*PI是已定義的宏名*/習(xí)慣上宏名用大寫字母表示,以便于與變量區(qū)別。第55頁(yè)/共72頁(yè)帶參宏定義格式:#define標(biāo)示符(形參表)形參表達(dá)式例如:#defineMAX(a,b)(a>b)?(a):(b)進(jìn)行宏替換時(shí),可以像使用函數(shù)一樣,通過實(shí)參與形參傳遞數(shù)據(jù)。第56頁(yè)/共72頁(yè)【例11-9】計(jì)算1到10的平方和。#include<stdio.h>#defineFUN(a)a*avoidmain(){inti;ints=0;for(i=1;i<=10;i++)s=s+FUN(i);printf("%d\n",s);}第57頁(yè)/共72頁(yè)注意宏名和括號(hào)之間不能有空格。有些參數(shù)表達(dá)式必須加括號(hào),否則會(huì)出現(xiàn)替換錯(cuò)誤,例如#defineS(x)x*x則S(5+6)并不是11的平方,而是:5+6*5+6結(jié)果為41。而如果宏定義為#defineS(x)(x)*(x)S(5+6)就會(huì)被替換為:(5+6)*(5+6)從而符合設(shè)計(jì)的要求了。這樣的問題在無參宏定義時(shí)也要注意:第58頁(yè)/共72頁(yè)注意函數(shù)要求實(shí)參與形參類型一致,而宏替換不需要。函數(shù)只有一個(gè)返回值,而宏替換可能有多個(gè)。函數(shù)影響運(yùn)行時(shí)間,而宏替換只影響編譯時(shí)間。
第59頁(yè)/共72頁(yè)11.4.2文件包含文件包含是把指定的文件插入該命令行位置取代該命令行。命令的一般形式為:#include<文件名>格式1或#include"文件名"格式2例如:#include"stdio.h"#include"math.h"第60頁(yè)/共72頁(yè)注意使用格式1時(shí),預(yù)處理程序在C編譯系統(tǒng)定義的標(biāo)準(zhǔn)目錄下查找指定的文件;使用格式2時(shí),預(yù)處理程序首先在當(dāng)前源文件所在目錄下查找指定文件,如沒找到,則在C編譯系統(tǒng)定義的標(biāo)準(zhǔn)目錄下查找指定的文件;一個(gè)#include命令只能包含一個(gè)文件,而且必須是文本文件文件包含可以嵌套,如a包含b,b包含c文件包含在程序設(shè)計(jì)中非常有用,像C語(yǔ)言中的頭文件,其中定義了很多外部變量或宏,在設(shè)計(jì)程序時(shí)只要包含進(jìn)來就可以了,不需要重復(fù)定義,節(jié)省了工作量,又可以避免出錯(cuò)。第61頁(yè)/共72頁(yè)11.4.3條件編譯條件編譯有三種形式,第一種形式:#ifdef
標(biāo)識(shí)符程序段1#else
程序段2#endif
【功能】如果標(biāo)識(shí)符已被#define命令定義過則對(duì)程序段1進(jìn)行編譯;否則對(duì)程序段2進(jìn)行編譯。如果沒有程序段2(它為空),本格式中的#else可以沒有,即可以寫為:#ifdef
標(biāo)識(shí)符程序段#endif
第62頁(yè)/共72頁(yè)【例11-10】條件編譯示例。#include<stdio.h>#defineNUM2008structstudent{intno;char*name;charsex;floatscore;}*s;voidmain(){s=(structstudent*)malloc(sizeof(structstudent));s->no=102;s->name="Zhangping";s->sex='M';s->score=62.5;#ifdefNUMprintf("Number=%d\nScore=%f\n",s->no,s->score);#elseprintf("Name=%s\nSex=%c\n",s->name,s->sex);#endiffree(s);}第63頁(yè)/共72頁(yè)11.4.3條件編譯第二種形式:#ifndef標(biāo)識(shí)符程序段1#else
程序段2#endif與第一種形式的區(qū)別是將“ifdef”改為“ifndef”。它的功能是,如果標(biāo)識(shí)符未被#define命令定義過則對(duì)程序段1進(jìn)行編譯,否則對(duì)程序段2進(jìn)行編譯。這與第一種形式的功能正相反。第64頁(yè)/共72頁(yè)11.4.3條件編譯第三種形式:
#if常量表達(dá)式
程序段1
#else
程序段2
#endif【功能】如常量表達(dá)式值為真(非0),則對(duì)程序段1進(jìn)行編譯,否則對(duì)程序段2進(jìn)行編譯。第65頁(yè)/共72頁(yè)11.5程序舉例【例11-11】將文件readme.txt中所有大寫字母改寫成小寫字母后保存,文件中其他字符不變。程序如下:
#include"stdio.h“
#include"stdlib.h“
#include"ctype.h“
main(
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- YY/T 0581.2-2024輸液連接件第2部分:無針連接件
- 貴州大學(xué)《生物防治學(xué)》2023-2024學(xué)年第一學(xué)期期末試卷
- 2025年貴州省安全員《C證》考試題庫(kù)及答案
- 2025湖北建筑安全員《C證》考試題庫(kù)
- 2025山西建筑安全員《A證》考試題庫(kù)及答案
- 硅湖職業(yè)技術(shù)學(xué)院《唐詩(shī)宋詞賞析》2023-2024學(xué)年第一學(xué)期期末試卷
- 貴陽(yáng)學(xué)院《物流英語(yǔ)》2023-2024學(xué)年第一學(xué)期期末試卷
- 2025年河北建筑安全員C證(專職安全員)考試題庫(kù)
- 2025海南省安全員考試題庫(kù)及答案
- 2025年-黑龍江省安全員《A證》考試題庫(kù)及答案
- 三支一扶協(xié)議書模板
- 燙傷的防治與護(hù)理
- 2024年全國(guó)職業(yè)院校技能大賽高職組(護(hù)理技能賽項(xiàng))備賽試題庫(kù)(含答案)
- 駕駛員三年內(nèi)工作總結(jié)
- 青年你為什么要入團(tuán)-團(tuán)員教育主題班會(huì)-熱點(diǎn)主題班會(huì)課件
- 司法鑒定工作應(yīng)急預(yù)案
- 《竹結(jié)構(gòu)建筑技術(shù)規(guī)程》
- 大一中國(guó)近代史綱要期末考試試題及答案
- (完整版)鋼筋加工棚驗(yàn)算
- 安徽省合肥市廬陽(yáng)區(qū)2023-2024學(xué)年三年級(jí)上學(xué)期期末數(shù)學(xué)試卷
- 概念方案模板
評(píng)論
0/150
提交評(píng)論