《程序設(shè)計(jì)與C語言》課件第9章_第1頁
《程序設(shè)計(jì)與C語言》課件第9章_第2頁
《程序設(shè)計(jì)與C語言》課件第9章_第3頁
《程序設(shè)計(jì)與C語言》課件第9章_第4頁
《程序設(shè)計(jì)與C語言》課件第9章_第5頁
已閱讀5頁,還剩62頁未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡介

第9章文件處理9.1C語言中的文件9.2文件類型指針9.3文件操作習(xí)題99.1C語言中的文件

C語言中的文件為流式文件,即把文件看做是一個(gè)有序的字符流。每個(gè)文件或者以文件結(jié)束標(biāo)志結(jié)束,或者在特定的字節(jié)號(hào)處結(jié)束(這個(gè)特定的字節(jié)號(hào)登記在由系統(tǒng)維護(hù)和管理的數(shù)據(jù)結(jié)構(gòu)中),如圖9-1所示。圖9-1由n個(gè)字符構(gòu)成的字符流(c文件)當(dāng)打開一個(gè)文件的時(shí)候,該文件就和某個(gè)流關(guān)聯(lián)起來。執(zhí)行程序會(huì)自動(dòng)打開三個(gè)標(biāo)準(zhǔn)文件——標(biāo)準(zhǔn)輸入文件、標(biāo)準(zhǔn)輸出文件和標(biāo)準(zhǔn)錯(cuò)誤文件以及與這三個(gè)文件相連的三種流——標(biāo)準(zhǔn)輸入流、標(biāo)準(zhǔn)輸出流和標(biāo)準(zhǔn)錯(cuò)誤流。流是文件和數(shù)據(jù)之間通信的通道。例如,標(biāo)準(zhǔn)輸入流能使程序讀取來自鍵盤的數(shù)據(jù),標(biāo)準(zhǔn)輸出流能使程序把數(shù)據(jù)輸出到屏幕上。從操作系統(tǒng)的角度看,任何和主機(jī)相連的輸入/輸出設(shè)備都是文件,這些文件稱為標(biāo)準(zhǔn)文件。根據(jù)它們?cè)谳斎?輸出時(shí)所起的不同作用,標(biāo)準(zhǔn)文件可分為標(biāo)準(zhǔn)輸入文件(如鍵盤)和標(biāo)準(zhǔn)輸出文件(如屏幕、打印機(jī))。從數(shù)據(jù)的組織來看,文件又分為兩類:文本文件和二進(jìn)制文件。文本文件又稱為ASCII文件,文件中的每個(gè)元素都是字符。例如源程序文件就是文本文件。二進(jìn)制文件是把數(shù)據(jù)轉(zhuǎn)換成二進(jìn)制形式后存儲(chǔ)起來的文件。在內(nèi)存中,所有的文件都要以二進(jìn)制形式存儲(chǔ),因此二進(jìn)制文件可以不經(jīng)轉(zhuǎn)換直接和內(nèi)存通信。對(duì)于文本文件來說,要把它存入內(nèi)存,中間就有個(gè)轉(zhuǎn)換成二進(jìn)制的過程,輸出時(shí)又要把二進(jìn)制形式轉(zhuǎn)換成字符形式,因而會(huì)影響速度。但文本文件有一個(gè)長處,就是在輸出時(shí)能以字符形式顯示文件的原有內(nèi)容,便于閱讀。對(duì)于二進(jìn)制文件來說,因?yàn)樗拿總€(gè)字節(jié)并不和字符相對(duì)應(yīng),因而在DOS狀態(tài)下用type命令輸出時(shí)會(huì)出現(xiàn)亂碼。下面看一下這兩種文件的差別。例如對(duì)于數(shù)據(jù)30000,它的文件形式和內(nèi)存形式之間的關(guān)系如圖9-2所示。圖9-2兩種文件形式與內(nèi)存形式之間的關(guān)系我們還應(yīng)該了解一下操作系統(tǒng)處理文件的方式。C語言目前使用的磁盤文件系統(tǒng)主要是“緩沖文件系統(tǒng)”。所謂緩沖文件系統(tǒng),是指在程序的數(shù)據(jù)區(qū)和磁盤文件之間并不是直接通信的,而是通過緩沖區(qū)相聯(lián)系的。所謂緩沖區(qū),實(shí)際上也是內(nèi)存中的一段空間。在輸入數(shù)據(jù)時(shí),先把數(shù)據(jù)從磁盤讀到“輸入緩沖區(qū)”中,等輸入緩沖區(qū)已滿或強(qiáng)制清空時(shí)再把其中的數(shù)據(jù)送到數(shù)據(jù)區(qū)進(jìn)行處理。處理后的數(shù)據(jù)要送入文件保存,但這也不是隨處理隨傳送的,而是先放到“輸出緩沖區(qū)”,等輸出緩沖區(qū)已滿或強(qiáng)制將其清空時(shí)再把其中的數(shù)據(jù)送到磁盤文件。也就是說,不一定每執(zhí)行一次輸入/輸出語句就實(shí)際訪問磁盤文件一次,而是多次讀/寫對(duì)應(yīng)一次磁盤訪問。緩沖區(qū)的大小隨機(jī)器而異,且由系統(tǒng)自動(dòng)設(shè)置,其大小一般為512字節(jié)或其整數(shù)倍。緩沖文件系統(tǒng)的示意圖如圖9-3所示。圖9-3緩沖文件系統(tǒng)的示意圖9.2文件類型指針文件指針在緩沖文件系統(tǒng)中處理磁盤文件時(shí)有重要的作用。要運(yùn)行一個(gè)文件,必須知道與該文件有關(guān)的信息,比如文件名、文件狀態(tài)、文件當(dāng)前的讀/寫位置、文件緩沖區(qū)的大小與位置等。這些信息被系統(tǒng)保存在一個(gè)結(jié)構(gòu)體中,這個(gè)結(jié)構(gòu)體中的信息組成了文件類型。系統(tǒng)為該類型起了個(gè)專用的名字:FILE。FILE類型的結(jié)構(gòu)和操作系統(tǒng)有關(guān),也就是說,該結(jié)構(gòu)的成員隨系統(tǒng)對(duì)文件處理方式的不同而不同。TurboC系統(tǒng)的文件結(jié)構(gòu)類型為:typedefstruct{intlevel; /*緩沖區(qū)被占用的程度*/unsignedflags; /*文件狀態(tài)標(biāo)記*/charfd: /*文件描述符*/unsignedcharhold; /*如無緩沖區(qū),則不讀取字符*/intbsize; /*緩沖區(qū)大小*/unsignedchar*buffer; /*文件緩沖區(qū)指針*/unsignedchar*curp; /*文件定位指針*/unsignedistemp; /*暫時(shí)文件指示器*/shorttoken; /*用于有效性檢查*/}FILE;

C語言程序要求,在對(duì)一個(gè)文件進(jìn)行處理時(shí),需首先定義一個(gè)FILE類型的指針,即建立一個(gè)FILE類型的指針變量,該指針變量用于指向系統(tǒng)內(nèi)存中的一個(gè)FILE類型的結(jié)構(gòu)體(即文件信息區(qū)),結(jié)構(gòu)體中保存著當(dāng)前處理文件的相關(guān)信息。文件指針的定義形式為:

FILE*〈文件指針名〉例如:

FILE*fp1,*fp2,*fp[3];則文件指針fp1和fp2可以指向某個(gè)文件結(jié)構(gòu)體而訪問該文件,文件指針數(shù)組fp中有3個(gè)文件的信息。9.3文件操作文件操作包括文件的打開與關(guān)閉、輸入與輸出、定位、文件錯(cuò)誤檢測及處理等。9.3.1文件的打開與關(guān)閉文件在使用之前必須打開,處理完之后必須關(guān)閉。

1.文件的打開文件的打開是通過調(diào)用fopen函數(shù)來實(shí)現(xiàn)的,其格式為:

〈文件指針〉=fopen(〈文件名〉,〈打開方式〉);其中:〈文件指針〉即類型為FILE的指針變量;〈文件名〉為DOS文件名,是一個(gè)字符串;〈打開方式〉也是個(gè)字符串,指出文件打開的目的。如:

FILE*fp;fp=fopen(″f1.txt″,″r″);說明把文件f1.txt以讀(r)的方式打開,函數(shù)的返回值是指向該被讀文件的指針。該指針由指針變量fp接收,于是fp就指向了f1.txt文件的信息區(qū)(FILE類型結(jié)構(gòu)體),也可以說指向了f1.txt文件,以后對(duì)fp的操作即為對(duì)該文件的操作。如果要打開的文件不在當(dāng)前目錄下,則應(yīng)該帶上路徑。例如:如果文件data.dat處在D盤的temp目錄下,則應(yīng)寫為:

fp=fopen(″D:\\temp\\data.dat″,″r″);其中的文件名是以字符串的形式出現(xiàn)的。在C語言中,字符串內(nèi)“\\”代表一個(gè)“\”字符,故路徑中的反斜杠分隔符雙寫。文件的打開方式列于表9-1中,其中列出了各種文件的打開方式,隱含的是打開ASCII文件。如果打開的是二進(jìn)制文件,則增加一個(gè)字符b(binary)。其他字符的含義為:r代表read,用于讀;w代表write,用于寫;a代表append,用于追加。

說明:①凡是打開方式字符串中含有字符“r”的,所打開的文件必須是已存在的文件,對(duì)不存在的文件不能打開讀。②凡是打開方式中帶有“w”字符的,所打開的文件可以是已經(jīng)存在的,也可以是尚不存在的。若不存在時(shí),則先要建立一個(gè)新文件,然后在里面寫內(nèi)容;若文件已經(jīng)存在,則會(huì)把原文件的內(nèi)容覆蓋掉,寫入新的內(nèi)容。③凡含有字符“a”的,以追加方式打開的文件也可以不存在。若不存在,則建立一個(gè)新文件,然后再追加;若已存在,則在文件的尾部追加。④以“r+”和“w+”方式打開的文件都是既可用于讀,又可用于寫的。其差別是,以“w+”方式打開的是一個(gè)新文件,應(yīng)先寫入內(nèi)容,然后可以讀。⑤在打開文件的操作中有可能出現(xiàn)故障,如當(dāng)文件所在的磁盤未準(zhǔn)備好時(shí),不能把文件打開,這時(shí)打開文件函數(shù)fopen就返回NULL值。因此,一般在進(jìn)行了打開文件的操作后,應(yīng)立即檢查一下打開操作是否成功。如已成功打開,則可繼續(xù)進(jìn)行;如果打開失敗,則應(yīng)顯示提示信息,并用exit()函數(shù)強(qiáng)制關(guān)閉所有文件,結(jié)束程序運(yùn)行并返回到操作系統(tǒng)狀態(tài)。這個(gè)過程常用的模式是:

if((fp=fopen(〈文件名〉,〈打開方式〉))==NULL){printf(″Openfail\n″); /*顯示打開失敗*/exit(0); /*結(jié)束程序*/}

(6)有三個(gè)和標(biāo)準(zhǔn)輸入/輸出流對(duì)應(yīng)的設(shè)備文件不需用戶打開,在執(zhí)行程序時(shí),系統(tǒng)自動(dòng)將它們打開。這三個(gè)文件是標(biāo)準(zhǔn)輸入文件、標(biāo)準(zhǔn)輸出文件和標(biāo)準(zhǔn)出錯(cuò)文件,指向它們的文件指針分別是stdin、stdout和stderr。

2.文件的關(guān)閉文件使用后必須及時(shí)關(guān)閉,以保護(hù)其中的數(shù)據(jù)。關(guān)閉就是使文件指針不再指向該文件,它可以再去指向其他文件。關(guān)閉文件的操作還有一個(gè)作用是清除緩沖區(qū)。在文件處理的最后,緩沖區(qū)中可能尚有一些數(shù)據(jù),關(guān)閉操作首先把這些數(shù)據(jù)送入磁盤文件,然后再釋放文件指針。因此,如果不關(guān)閉文件,則留在緩沖區(qū)中的數(shù)據(jù)就會(huì)丟失。關(guān)閉文件用fclose函數(shù),其格式為:

fclose(〈文件指針名〉);如:

fclose(fp);則使fp不再指向剛才它所指的文件。如果關(guān)閉成功,則fclose函數(shù)的返回值是0;如果關(guān)閉失敗,則返回值是EOF(即-1)。9.3.2文件的輸入與輸出文件的輸入/輸出操作一般是按以下步驟進(jìn)行的:

(1)用fopen函數(shù)打開文件。

(2)對(duì)文件進(jìn)行讀/寫操作。

(3)用fclose函數(shù)關(guān)閉文件。對(duì)已打開的文件的輸入/輸出操作是通過文件指針進(jìn)行的,實(shí)際上它們是由一些標(biāo)準(zhǔn)的讀/寫函數(shù)完成的。所謂文件的輸入,是指用一些具有讀功能的函數(shù)把磁盤文件中的數(shù)據(jù)讀入內(nèi)存;所謂文件的輸出,是指用一些具有寫功能的函數(shù)把內(nèi)存中的數(shù)據(jù)寫入磁盤文件。

1.文件的字符輸入函數(shù)fgetc和字符輸出函數(shù)fputc

1)fgetc函數(shù)

fgetc函數(shù)的調(diào)用格式為:

〈字符變量〉=fgetc(〈文件指針〉);功能:從〈文件指針〉所指的文件中讀入一個(gè)字符賦給〈字符變量〉(在內(nèi)存中)。例如:

charc;FILE*fp;fp=fopen(″filein.txt″,″r″);if(fp!=NULL) c=fgetc(fp);文件讀/寫過程中,有一個(gè)文件定位指針時(shí)刻指向正在操作的位置,它會(huì)隨著讀/寫操作的進(jìn)行而變化。fgetc函數(shù)就把文件定位指針當(dāng)前位置處的字符讀出,并將其轉(zhuǎn)換成ASCII碼值,返回給字符變量。如果讀取失敗或到文件末尾,fgetc函數(shù)將返回一個(gè)文件結(jié)束標(biāo)志EOF(即-1)。EOF不是可顯示字符,不能在屏幕上出現(xiàn)。字符的ASCII碼不可能為-1,故可將EOF視作文本文件的結(jié)束標(biāo)志。但對(duì)二進(jìn)制文件則不然,因?yàn)槎M(jìn)制文件某個(gè)字節(jié)中的數(shù)據(jù)可能是-1,如把-1作為文件結(jié)束標(biāo)志,則會(huì)失去-1之后的所有數(shù)據(jù),所以ANSIC提供了一個(gè)判斷文件是否結(jié)束的函數(shù)feof,其參數(shù)為文件指針。如文件結(jié)束,則feof(fp)的值為1,否則feof(fp)的值為0。這個(gè)函數(shù)對(duì)于文本文件也適用。如果fp為標(biāo)準(zhǔn)輸入文件指針stdin,則fgetc函數(shù)的功能就是從鍵盤上輸入字符,這和getchar函數(shù)是一樣的,即

fgetc(stdin)=getchar()實(shí)際上,這個(gè)工作已在<stdio.h>頭文件中用宏定義的形式作了說明: #definegetchar()fgetc(stdin)

2)fputc函數(shù)設(shè)ch為字符類型,則其調(diào)用格式為:

fputc(ch,〈文件指針〉);功能:把字符ch(變量或常量)放入〈文件指針〉所指的文件中。如果操作失敗,則返回一個(gè)EOF。如果文件指針為標(biāo)準(zhǔn)輸出文件指針stdout,則有:

fputc(ch,stdout)=putchar(ch)這也在頭文件<stdio.h>中作了宏定義: #defineputchar(ch)fputc(ch,stdout)對(duì)標(biāo)準(zhǔn)輸入/輸出文件而言,用getchar()和putchar()更為簡單。

3)用字符輸入/輸出函數(shù)處理文件看下面的例子。

【例9-1】文本文件復(fù)制。把文件c:\f1.bat進(jìn)行復(fù)制,新文件為a:\f2.bat。#include<stdio.h>main(){FILE*fp1,*fp2;charc;if(((fp1=fopen(″c:\\f1.bat″,″r″))==NULL)||((fp2=fopen(″a:\\f2.bat″,″w″))==NULL)){printf(″openfail\n″);exit(0);}while(!feof(fp1)){c=fgetc(fp1);fputc(c,fp2);}fclose(fp1);fclose(fp2);return0;}該程序是把c盤上的批處理文件拷貝到a盤上。c盤上的文件作為數(shù)據(jù)的提供者,以“r”方式打開;a盤上的文件作為數(shù)據(jù)接收者,以“w”方式打開。while(!feof(fp1))等價(jià)于while(feof(fp1)==0),即文件fp1未結(jié)束時(shí)執(zhí)行循環(huán)操作。

【例9-2】實(shí)現(xiàn)操作系統(tǒng)命令提示符下的文件連接功能,如命令

c:\>appendfile1file2實(shí)現(xiàn)把文件file1追加到文件file2的末尾。程序如下:#include<stdio.h>main(intargc,char*argv[]){FILE*fp1,*fp2;intc;if(argc!=3){printf(″USAGE:file1file2\n″);exit(0);}if(((fp1=fopen(argv[1],″r″))==NULL)||((fp2=fopen(argv[2],″a″))==NULL)){printf(″Openfail\n″);exit(0);}while((c=fgetc(fp1))!=EOF)

fputc(c,fp2);fclose(fp1);fclose(fp2);return0;}該程序中的main函數(shù)必須帶參數(shù)。文件fp1以讀方式打開。文件fp2以追加方式打開后,文件指針自動(dòng)指向其末尾,后面進(jìn)行的讀/寫操作是從fp1文件上一個(gè)個(gè)地讀字符,并一個(gè)個(gè)地放入fp2文件中,直到遇到文件結(jié)束符為止。將該程序進(jìn)行編譯、連接后,如果將生成的可執(zhí)行文件取名為append,那么它就相當(dāng)于一個(gè)DOS命令了。

2.文件的字符串輸入/輸出函數(shù)fgets()和fputs

1)fgets()函數(shù)

fgets函數(shù)的調(diào)用格式為:

fgets(str,n,fp);其中,str為指定的字符數(shù)組;n為包括“\0”字符在內(nèi)的字符個(gè)數(shù);fp為文件指針。功能:從fp所指文件中讀取n-1個(gè)字符(留一個(gè)字符給′\0′),并把它們放入str字符數(shù)組中。當(dāng)滿足下列條件之一時(shí),讀取結(jié)束:

(1)已經(jīng)讀取了n-1個(gè)字符。

(2)當(dāng)前讀到的字符為回車符。

3)已讀到文件的末尾。不管是以哪種情況結(jié)束,系統(tǒng)都會(huì)把空字符′\0′加到所讀字符串的最后,即使讀入的是回車符。例如,設(shè)讀取的字符串為“china〈CR〉”,則在內(nèi)存緩沖區(qū)中的存儲(chǔ)形式為:由此可以看出,把fgets函數(shù)作用到標(biāo)準(zhǔn)輸入指針stdin之后,其功能和gets函數(shù)并不完全相同,即:

fgets(str,n,stdin)≠gets(str)因?yàn)樵谟胓ets函數(shù)時(shí)是把回車符轉(zhuǎn)換成空字符′\0′加在字符串尾部,而fgets函數(shù)是把讀入的回車符保存起來,另外再加一個(gè)′\0′符號(hào)。china<CR>\0

2)fputs函數(shù)

fputs函數(shù)的調(diào)用格式為:

fputs(str,fp);其中,fp為文件指針,str為一字符串,它可以是指向字符串的指針,也可以是字符數(shù)組名,還可以是字符串常量。功能:把指定的字符串放到指定的文件中。

fputs函數(shù)在將字符串寫入文件時(shí),把字符串后的′\0′字符自動(dòng)舍去。同樣有

fputs(str,stdout)≠puts(str)因?yàn)閜uts()函數(shù)是把字符串尾部的′\0′字符變成回車符輸出,而fputs函數(shù)則是舍去字符串末尾的′\0′字符。

fputs函數(shù)若輸出成功,則返回值為0;若輸出失敗,則返回值為EOF(即-1)。

【例9-3】fputs函數(shù)的應(yīng)用。#include<stdio.h>main(){charstr[10];gets(str);puts(str);puts(str);putchar(′\n′);fputs(str,stdout);fputs(str,stdout);return0;}運(yùn)行輸出:

very↙ /*輸入*/very /*兩個(gè)puts的輸出*/veryveryvery /*兩個(gè)fputs的輸出*/分析運(yùn)行結(jié)果可以看出:輸入中的回車符變?yōu)椤洌?′附在最后;用puts函數(shù)輸出時(shí)遇到′\0′變?yōu)榛剀嚪麚Q行,因此有兩行“very”。在輸出第二個(gè)“very”并換行后又執(zhí)行putchar(′\n′),則又空出一行。當(dāng)遇到fputs時(shí),輸出“very”后不換行,則第二個(gè)“very”就在同一行輸出了。仍用上面的例子,如果把其中的gets(str)換成fgets(str,10,stdin),則執(zhí)行后的輸出結(jié)果是:

very↙ /*輸入*/very /*空1行*/very /*空兩行*/veryvery請(qǐng)分析為什么會(huì)出現(xiàn)這樣的結(jié)果。

【例9-4】將一個(gè)磁盤文件上的內(nèi)容加上行序號(hào)顯示在屏幕上,并復(fù)制到另一個(gè)磁盤文件中。#include<stdio.h>

#include<stdlib.h>main(intargc,char*argv[]){charbuff[256];FILE*fp1,*fp2;intline;if(argc!=3){puts(″3parameters\n″);

exit(0);

}if(((fp1=fopen(argv[1],″r″))=NULL||((fp2=fopen(argv[2],″w″))=NULL)){printf(″Openfail\n″);

exit(0);

}line=1;while(fgets(buff,256,fp1)!=NULL){printf(″%3d:%s″,line++,buff);fputs(buff,fp2);}fclose(fp1);fclose(fp2);return0;

}函數(shù)fgets從fp1文件中輸入一行字符送入buff緩沖區(qū)中,然后用printf函數(shù)語句把它的行號(hào)與buff中的字符串送到顯示器顯示,又用fputs函數(shù)把該行送入文件fp2中。這是在DOS命令提示符下進(jìn)行的操作,所以在把程序編譯、連接后,生成.exe文件,設(shè)文件名為fcopy,則在執(zhí)行

c:\>fcopyfile1.txtfile2.txt之后,file1中的內(nèi)容既在屏幕上顯示,又被復(fù)制到文件file2中。

3.文件數(shù)據(jù)塊的輸入/輸出函數(shù)fread和fwrite

fgetc和fputc函數(shù)一次只能讀和寫一個(gè)字符,fgets和fputs函數(shù)一次只能讀和寫不能確定字符個(gè)數(shù)的一串字符。但是,在程序的應(yīng)用中,我們常常需要能夠一次讀/寫有一定字符長度的數(shù)據(jù),比如一個(gè)記錄等,為此C語言又提供了兩個(gè)這樣的讀/寫函數(shù)即fread和fwrite函數(shù)。

1)fread函數(shù)

fread函數(shù)調(diào)用的一般格式為:

fread(buf,size,count,fp);其中buf是一個(gè)指針,指向輸入數(shù)據(jù)在內(nèi)存中的起始地址;size為要讀取的字節(jié)個(gè)數(shù);count為要讀取多少個(gè)size字節(jié)的數(shù)據(jù)項(xiàng);fp為指向由fopen打開的文件的指針。功能:從由fp指定的文件中讀取size*count個(gè)字節(jié)的數(shù)據(jù),并把它放入由buf指定的內(nèi)存中。當(dāng)文件以二進(jìn)制形式打開(即fp=fopen(″file1″,″rb″);)時(shí),fread函數(shù)就可以用來讀取各種類型的數(shù)據(jù)信息。如:

fread(fbuf,sizeof(float),4,fp);則從由fp指定的文件中讀出4個(gè)大小為sizeof(float)的數(shù)據(jù)放入fbuf中,fbuf為一實(shí)型數(shù)組名,也是其第一個(gè)元素的地址。

fread函數(shù)的返回值:若讀取成功,則返回讀取的項(xiàng)數(shù)即count值;若讀取失敗,則返回-1。

2)fwrite函數(shù)

fwrite函數(shù)調(diào)用的格式為:

fwrite(buf,size,count,fp);其中,參數(shù)的個(gè)數(shù)和類型與fread函數(shù)完全一樣,只是它進(jìn)行相反的操作。這里的buf是輸出數(shù)據(jù)在內(nèi)存中存放的地址。功能:把buf中大小為size*count個(gè)字節(jié)的數(shù)據(jù)寫入由fp指定的文件中。如語句:

fwrite(ibuf,2,5,fp);是把整型數(shù)組中的5個(gè)整數(shù)寫入由fp指定的文件中。返回值:若輸出成功,則返回寫入文件中的數(shù)據(jù)項(xiàng)數(shù);若輸出失敗,則返回-1。常常聯(lián)合使用fread和fwrite函數(shù)對(duì)二進(jìn)制文件進(jìn)行讀/寫。

【例9-5】從鍵盤錄入n個(gè)學(xué)生的準(zhǔn)考證號(hào)、姓名、總分,把這些數(shù)據(jù)保存到磁盤文件kaosheng.lst中,然后再從磁盤文件中讀出并在屏幕上顯示出來。#include<stdio.h>

#defineN500structstudent{unsignedlongno;charname[15];floatscore;}stud[N];

typedefstructstudentSTU;voidsave(void);voidload(void);intm=0;main(){inti;printf(″Inputstudentnumberm:1≤m≤%d\n″,N);scanf(″%d″,&m);for(i=0;i<m;i++)scanf(″%lu%s%f″,&stud[i].no,stud[i].name,&stud[i].score);save();load();return0;}voidsave(void){FILE*fp;inti;if((fp=fopen(″A:\\kaosheng.lst″,″wb″))==NULL){printf(″Openfail\n″);exit(0);}for(i=0;i<m;i++)if(fwrite(&stud[i],sizeof(STU),1,fp)!=1){printf(″Filewriteerror!\n″);exit(0);}fclose(fp);

}voidload(void){inti;FILE*fp;if((fp=fopen(″A:\\kaosheng.lst″,″rb″))==NULL){printf(″Openfail\n″);exit(0);

}for(i=0;i<m;i++){if(fread(&stud[i],sizeof(STU),1,fp)!=1){printf(″Filereaderror\n″);exit(0);

}printf(″No:%lu\tName:%s\tscore:%f\n″,stud[i].no,stud[i].name,stud[i].score);}fclose(fp);

}在save和load函數(shù)中都是用if語句的條件判斷,即利用fwrite和fread函數(shù)成功執(zhí)行后返回寫入和讀出的數(shù)據(jù)塊的項(xiàng)數(shù)的特點(diǎn)來完成輸入/輸出工作的,這使程序顯得非常簡潔;另外使用typedef把一個(gè)長的結(jié)構(gòu)體類型名structstudent簡稱為STU,這樣在程序中簡化了書寫。程序中預(yù)留出500個(gè)考生的位置,根據(jù)實(shí)際參加考試的人數(shù)決定數(shù)組實(shí)際使用的大小。用全局變量m來表示實(shí)際人數(shù),它可在多個(gè)函數(shù)中使用。在主函數(shù)main中,首先執(zhí)行把信息從鍵盤輸入到內(nèi)存的操作,即把m個(gè)考生的準(zhǔn)考證號(hào)(準(zhǔn)考證號(hào)很長,所以定義為無符號(hào)長整型,對(duì)其輸入/輸出時(shí)相應(yīng)的控制符為“%lu”)、姓名和總分輸入到內(nèi)存,然后調(diào)用save函數(shù),將這些數(shù)據(jù)寫入以kaosheng.lst命名的磁盤文件中。fwrite函數(shù)一次將一個(gè)長度為sizeof(STU)(即結(jié)構(gòu)體各分量長度之和:4+15+4=23)個(gè)字節(jié)的數(shù)據(jù)塊寫入kaosheng.lst文件中,共m個(gè)學(xué)生的數(shù)據(jù)。接著再調(diào)用load函數(shù),從磁盤文件kaosheng.lst中讀出已存入的學(xué)生數(shù)據(jù),并把它們顯示在屏幕上,形如:

No:03008942Name:Zhangyi598.5No:03008943Name:Wangyue632.5函數(shù)save和load的參數(shù)類型都是void,它們和主函數(shù)之間的信息傳遞不是通過參數(shù),而是通過全局變量來實(shí)現(xiàn)的。我們考察一下數(shù)據(jù)從鍵盤輸入到屏幕輸出的整個(gè)過程中所發(fā)生的現(xiàn)象:由鍵盤輸入的是字符(文本文件),送入計(jì)算機(jī)內(nèi)存時(shí)把回車、換行兩個(gè)字符轉(zhuǎn)換成一個(gè)換行符;從內(nèi)存中以“wb”(二進(jìn)制寫)方式輸出到磁盤文件,不需要轉(zhuǎn)換,是按內(nèi)存的形式輸出到文件的;再以“rb”(二進(jìn)制讀)方式把磁盤文件讀入內(nèi)存中,也不需任何轉(zhuǎn)換,是按其原始形式進(jìn)行輸入的;最后用printf函數(shù)將內(nèi)存中的數(shù)據(jù)輸出到屏幕上,是將二進(jìn)制文件轉(zhuǎn)換成文本文件,又把換行符轉(zhuǎn)換成回車、換行兩個(gè)字符。對(duì)同一個(gè)文件進(jìn)行讀/寫操作時(shí),必須以同一種組織方式打開,即都以文本格式打開或都以二進(jìn)制格式打開。

fread和fwrite函數(shù)一般用于二進(jìn)制文件的輸入/輸出,因?yàn)樗前粗付ù笮〈鎯?chǔ)數(shù)據(jù)塊的,而數(shù)據(jù)塊都是由有效數(shù)據(jù)項(xiàng)組成的。從二進(jìn)制文件中讀一個(gè)結(jié)構(gòu)體信息時(shí),能把結(jié)構(gòu)體各個(gè)分量數(shù)據(jù)完整地讀進(jìn)來。而如果從鍵盤上讀,如

fread(&stud[i],sizeof(STU),1,stdin);那么當(dāng)你輸入的數(shù)據(jù)中含有空格時(shí),如

0398772zhaori599則該函數(shù)就只輸入sizeof(STU)個(gè)字符到stud[i]中,其中包含空格等分隔符,這樣一來,各分量的數(shù)據(jù)可能就不是你所希望的了。

4.文件的格式化輸入/輸出函數(shù)fscanf和fprintf這兩個(gè)函數(shù)的調(diào)用格式分別是:

fscanf(〈文件指針〉,〈格式控制串〉,〈輸入列表〉);

fprintf(〈文件指針〉,〈格式控制串〉,〈輸出列表〉);它們的作用與scanf函數(shù)和printf函數(shù)幾乎一樣,差別就在于它們可以對(duì)任何文件進(jìn)行輸入/輸出,而scanf和printf只對(duì)終端設(shè)備進(jìn)行。因此使用fscanf和fprintf函數(shù)時(shí)應(yīng)該帶一個(gè)文件指針。如

fscanf(fp,″%d%f″,&i,&x);表示從fp所指文件中讀入一個(gè)整數(shù)給i,讀入一個(gè)浮點(diǎn)數(shù)給x(這樣做要非常小心,必須先要知道磁盤上的數(shù)據(jù)是如何存儲(chǔ)的)。而

fprintf(fp,″%d%s″,i,″China″);則把整數(shù)i和字符串“China”寫入fp所指的文件中。當(dāng)文件指針為stdin和stdout時(shí),fscanf和fprintf的作用就與scanf和printf完全相同了,即

fscanf(stdin,″…″,…)=scanf(″…″,…)fprintf(stdout,″…″,…)=printf(″…″,…)用函數(shù)fscanf和fprintf對(duì)磁盤文件進(jìn)行讀/寫的優(yōu)點(diǎn)是方便,容易理解;缺點(diǎn)是運(yùn)行速度較慢,因?yàn)樗鼈冊(cè)谳斎霑r(shí)要將ASCII碼轉(zhuǎn)換成二進(jìn)制形式,輸出時(shí)又要將二進(jìn)制形式轉(zhuǎn)換成ASCII碼字符。顯然,如果在磁盤文件與內(nèi)存之間頻繁交換數(shù)據(jù)的情況下使用fscanf和fprintf,則程序的效率是很低的,此時(shí)最好采用數(shù)據(jù)塊輸入/輸出函數(shù)fread和fwrite。9.3.3文件的定位我們已經(jīng)知道,C語言中的文件是流式文件,處理文件的方式是順序處理。文件一打開,就有一個(gè)定位指針指向規(guī)定的地方,隨著讀/寫的進(jìn)行,定位指針自動(dòng)向下移動(dòng)。但在很多情況下需要改變這種順序讀/寫的方法,即能任意指定讀/寫位置,為此C語言又提供了相應(yīng)的函數(shù),主要有:返回文件定位指針當(dāng)前位置的函數(shù)ftell()、重新把文件定位指針置于文件頭的函數(shù)rewind()和改變文件定位指針當(dāng)前位置的函數(shù)fseek()。

1.ftell函數(shù)該函數(shù)的功能是返回文件定位指針的當(dāng)前位置,即相對(duì)于文件頭的位移量(長整型),文件頭的位置定為0。函數(shù)的參數(shù)是文件指針。如果該函數(shù)運(yùn)行不正常,則返回值為-1L,表示出錯(cuò)。程序中可利用返回值來判斷函數(shù)調(diào)用是否出錯(cuò),如

i=ftell(fp);

if(i==-1L)printf(″ERROR\n″);當(dāng)文件剛打開時(shí),ftell返回值為0L。

2.rewind函數(shù)該函數(shù)的功能是把文件定位指針重新拉回到文件開頭,這在對(duì)文件進(jìn)行多遍操作時(shí)非常有用,即不需要反復(fù)進(jìn)行文件關(guān)閉與打開操作,只需調(diào)用rewind函數(shù)即可。其調(diào)用格式為:

rewind(fp);表示把fp所指文件的定位指針拉回到文件頭,不管它現(xiàn)在處于什么位置。

3.fseek函數(shù)該函數(shù)的功能是把文件定位指針設(shè)置到需要的地方。該函數(shù)的調(diào)用格式為:

fseek(〈文件指針〉,〈位移量〉,〈起始點(diǎn)〉);其中,〈位移量〉是長整型,長整型的標(biāo)志是整型數(shù)據(jù)后加字符“L”;位移量可正可負(fù),正代表向后(尾),負(fù)代表向前(頭);〈起始點(diǎn)〉即位移的參照點(diǎn),共有三個(gè),可以用名字,也可用相應(yīng)的數(shù)字表示,具體情況如表9-2所示。例如:

fseek(fp,50L,0);/*定位于距文件頭50個(gè)字節(jié)處*/fseek(fp,-25L,1); /*定位于當(dāng)前位置前25個(gè)字節(jié)處*/fseek(fp,-10L,2); /*定位于文件尾前10個(gè)字節(jié)處*/顯然當(dāng)起始點(diǎn)在文件開頭時(shí),位移量只能為正;當(dāng)起始點(diǎn)在文件尾時(shí),位移量只能為負(fù)。

【例9-6】設(shè)文件stu.txt中存有40名學(xué)生的信息,學(xué)號(hào)從1~40編號(hào)。將學(xué)生的信息按學(xué)號(hào)的奇偶分為兩組,分別加以輸出。#include<stdio.h>

#defineN40structstudent{intno;charname[15];floatscore;}stud[N];

typedefstructstudentSTU;main(){FILE*fp;inti,n;if((fp=fopen(″a:\\stu.txt″,″rb″)==NULL){printf(″Openfail\n″);exit(0);}printf(″Listoddno.students:\n″); if(N%2==0) n=N/2; else n=N/2+1; for(i=0;i<N/2;i++) {fseek(fp,2*i*sizeof(STU),0);if(fread(&stud[i],sizeof(STU),1,fp)!=1){printf(″Filereaderror!\n″);exit(0);}printf(″No:%d\tNAME:%s\tScore:%f\n″,

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(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ì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論