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

下載本文檔

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

文檔簡介

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

(2)對文件進行讀/寫操作。

(3)用fclose函數(shù)關(guā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(〈文件指針〉);功能:從〈文件指針〉所指的文件中讀入一個字符賦給〈字符變量〉(在內(nèi)存中)。例如:

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

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

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

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

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

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

【例9-1】文本文件復制。把文件c:\f1.bat進行復制,新文件為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))等價于while(feof(fp1)==0),即文件fp1未結(jié)束時執(zhí)行循環(huán)操作。

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

c:\>appendfile1file2實現(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以追加方式打開后,文件指針自動指向其末尾,后面進行的讀/寫操作是從fp1文件上一個個地讀字符,并一個個地放入fp2文件中,直到遇到文件結(jié)束符為止。將該程序進行編譯、連接后,如果將生成的可執(zhí)行文件取名為append,那么它就相當于一個DOS命令了。

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

1)fgets()函數(shù)

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

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

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

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

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

fgets(str,n,stdin)≠gets(str)因為在用gets函數(shù)時是把回車符轉(zhuǎn)換成空字符′\0′加在字符串尾部,而fgets函數(shù)是把讀入的回車符保存起來,另外再加一個′\0′符號。china<CR>\0

2)fputs函數(shù)

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

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

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

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

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

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

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

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

【例9-4】將一個磁盤文件上的內(nèi)容加上行序號顯示在屏幕上,并復制到另一個磁盤文件中。#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ù)語句把它的行號與buff中的字符串送到顯示器顯示,又用fputs函數(shù)把該行送入文件fp2中。這是在DOS命令提示符下進行的操作,所以在把程序編譯、連接后,生成.exe文件,設(shè)文件名為fcopy,則在執(zhí)行

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

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

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

1)fread函數(shù)

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

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

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

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

2)fwrite函數(shù)

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

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

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

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

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

fread和fwrite函數(shù)一般用于二進制文件的輸入/輸出,因為它是按指定大小存儲數(shù)據(jù)塊的,而數(shù)據(jù)塊都是由有效數(shù)據(jù)項組成的。從二進制文件中讀一個結(jié)構(gòu)體信息時,能把結(jié)構(gòu)體各個分量數(shù)據(jù)完整地讀進來。而如果從鍵盤上讀,如

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

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

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

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

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

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

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

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

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

i=ftell(fp);

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

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

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

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

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

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

【例9-6】設(shè)文件stu.txt中存有40名學生的信息,學號從1~40編號。將學生的信息按學號的奇偶分為兩組,分別加以輸出。#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等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
  • 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論