第13章 文件.ppt_第1頁
第13章 文件.ppt_第2頁
第13章 文件.ppt_第3頁
第13章 文件.ppt_第4頁
第13章 文件.ppt_第5頁
已閱讀5頁,還剩71頁未讀, 繼續(xù)免費閱讀

下載本文檔

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

文檔簡介

1、第13章 文 件,13.1文件概述 13.2文件類型指針 13.3文件的打開與關(guān)閉 13.4文件的讀寫 13.5文件的定位 13.6出錯的檢測 13.7文件輸入輸出小結(jié) 習(xí)題,13.1C文件概述 文件(file)是程序設(shè)計中一個重要的概念。所謂“文件”一般指存儲在外部介質(zhì)上數(shù)據(jù)的集合。一批數(shù)據(jù)是以文件的形式存放在外部介質(zhì)(如磁盤)上的。操作系統(tǒng)是以文件為單位對數(shù)據(jù)進(jìn)行管理的,也就是說,如果想找存在外部介質(zhì)上的數(shù)據(jù),必須先按文件名找到所指定的文件,然后再從該文件中讀取數(shù)據(jù)。要向外部介質(zhì)上存儲數(shù)據(jù)也必須先建立一個文件(以文件名標(biāo)識),才能向它輸出數(shù)據(jù)。 以前各章中所用到的輸入和輸出,都是以終端為對

2、象的,即從終端鍵盤輸入數(shù)據(jù),運(yùn)行結(jié)果輸出到終端上。從操作系統(tǒng)的角度看,每一個與主機(jī)相聯(lián)的輸入輸出設(shè)備都看作是一個文件。例如,終端鍵盤是輸入文件,,顯示屏和打印機(jī)是輸出文件。 在程序運(yùn)行時,常常需要將一些數(shù)據(jù)(運(yùn)行的最終結(jié)果或中間數(shù)據(jù))輸出到磁盤上存放起來,以后需要時再從磁盤中輸入到計算機(jī)內(nèi)存。這就要用到磁盤文件。 C語言把文件看作是一個字符(字節(jié))的序列,即由一個一個字符(字節(jié))的數(shù)據(jù)順序組成。根據(jù)數(shù)據(jù)的組織形式,可分為ASCII文件和二進(jìn)制文件。ASCII文件又稱文本(text)文件,它的每一個字節(jié)放一個ASCII代碼,代表一個字符。二進(jìn)制文件是把內(nèi)存中的數(shù)據(jù)按其在內(nèi)存中的存儲形式原樣輸出到

3、磁盤上存放。如果有一個整數(shù)10000,在內(nèi)存中占2個字節(jié),如果按ASCII碼形式輸出,則占5個字節(jié),,而按二進(jìn)制形式輸出,在磁盤上只占2個字節(jié),見圖13.1。用ASCII碼形式輸出與字符一一對應(yīng),一個字節(jié)代表一個字符,一個字節(jié)代表一個字符,因而便于對字符進(jìn)行逐個處理,也便于輸出字符。但一般占存儲空間較多,而且要花費轉(zhuǎn)換時間(二進(jìn)制形式與ASCII碼間的轉(zhuǎn)換)。用二進(jìn)制形式輸出數(shù)值,可以節(jié)省外存空間和轉(zhuǎn)換時間,但一個字節(jié)并不對應(yīng)一個字符,不能直接輸出字符形式。一般中間結(jié)果數(shù)據(jù)需要暫時保存在外存上以后又需要輸入到內(nèi)存的,常用二進(jìn)制文件保存。,圖13.1 由前所述,一個C文件是一個字節(jié)流或二進(jìn)制流。

4、它把數(shù)據(jù)看作是一連串的字符(字節(jié)),而不考慮記錄的界限。換句話說,C語言中文件并不是由記錄(record)組成的(這是和PASCAL或其他高級語言不同的)。在C語言中對文件的存取是以字符(字節(jié))為單位的。輸入輸出的數(shù)據(jù)流的開始和結(jié)束僅受程序控制而不受物理符號(如回車換行符)控制。,也就是說,在輸出時不會自動增加回車換行符以作為記錄結(jié)束的標(biāo)志,輸入時不以回車換行符作為記錄的間隔(事實上C文件并不由記錄構(gòu)成)。我們把這種文件稱為流式文件。C語言允許對文件存取一個字符,這就增加了處理的靈活性。 在過去使用的C版本(如UNIX系統(tǒng)下使用的C)有兩種對文件的處理方法:一種叫“緩沖文件系統(tǒng)”,一種叫“非緩

5、沖文件系統(tǒng)”。所謂緩沖文件系統(tǒng)是指系統(tǒng)自動地在內(nèi)存區(qū)為每一個正在使用的文件名開辟一個緩沖區(qū)。從內(nèi)存向磁盤輸出數(shù)據(jù)必須先送到內(nèi)存中的緩沖區(qū),裝滿緩沖區(qū)后才一起送到磁盤去。如果從磁盤向內(nèi)存讀入數(shù)據(jù),則一次從磁盤文件將一批數(shù)據(jù)輸入到內(nèi)存緩沖區(qū)(充滿緩沖區(qū)),然后再,圖13.2,從緩沖區(qū)逐個地將數(shù)據(jù)送到程序數(shù)據(jù)區(qū)(給程序變量)。見圖13.2。緩沖區(qū)的大小由各個具體的C版本確定,一般為512字節(jié)。,所謂“非緩沖文件系統(tǒng)”是指系統(tǒng)不自動開辟確定大小的緩沖區(qū),而由程序為每個文件設(shè)定緩沖區(qū)。 在UNIX系統(tǒng)下,用緩沖文件系統(tǒng)來處理文本文件,用非緩沖文件系統(tǒng)處理二進(jìn)制文件。用緩沖文件系統(tǒng)進(jìn)行的輸入輸出又稱為高級

6、(或高層)磁盤輸入輸出(高層I/O),用非緩沖文件系統(tǒng)進(jìn)行的輸入輸出又稱為低級(低層)輸入輸出系統(tǒng)。ANSI C標(biāo)準(zhǔn)決定不采用非緩沖文件系統(tǒng),而只采用緩沖文件系統(tǒng)。即既用緩沖文件系統(tǒng)處理文本文件,也用它來處理二進(jìn)制文件。也就是將緩沖文件系統(tǒng)擴(kuò)充為可以處理二進(jìn)制文件。 在C語言中,沒有輸入輸出語句,對文件的讀寫都是用庫函數(shù)來實現(xiàn)的。ANSI規(guī)定了標(biāo)準(zhǔn)輸入輸,出函數(shù),用它們對文件進(jìn)行讀寫。 本章只介紹ANSI C規(guī)定的文件系統(tǒng)以及對它的讀寫。 13.2文件類型指針 緩沖文件系統(tǒng)中,關(guān)鍵的概念是“文件指針”。每個被使用的文件都在內(nèi)存中開辟一個區(qū),用來存放文件的有關(guān)信息(如文件的名字、文件狀態(tài)及文件當(dāng)

7、前位置等)。這些信息是保存在一個結(jié)構(gòu)體變量中的。該結(jié)構(gòu)體類型是由系統(tǒng)定義的,取名為FILE。Turbo C在stdio.h文件中有以下的文件類型聲明:,typedefstruct shortlevel; /*緩沖區(qū)“滿”或“空”的程度*/ unsignedflags; /*文件狀態(tài)標(biāo)志*/ charfd; /*文件描述符*/ unsignedcharhold; /*如無緩沖區(qū)不讀取字符*/ shortbsize; /*緩沖區(qū)的大小*/ unsignedchar*baffer;/*數(shù)據(jù)緩沖區(qū)的位置*/ unsignedar*curp;/*指針,當(dāng)前的指向*/ unsignedistemp;/*臨

8、時文件,指示器*/ shorttoken;/*用于有效性檢查*/ FILE;,有了結(jié)構(gòu)體FILE類型之后,可以用它來定義若干個FILE類型的變量,以便存放若干個文件的信息。例如,可以定義以下FILE類型的數(shù)組。FILEf5;定義了一個結(jié)構(gòu)體數(shù)組f,它有5個元素,可以用來存放5個文件的信息。 可以定義文件型指針變量。如: FILEfp; fp是一個指向FILE類型結(jié)構(gòu)體的指針變量??梢允筬p指向某一個文件的結(jié)構(gòu)體變量,從而通過該結(jié)構(gòu)體變量中的文件信息能夠訪問該文件。也就是說,通過文件指針變量能夠找到與它相關(guān)的文件。如果有n個文件,一般應(yīng)設(shè)n個指針變量(指向FILE類型結(jié)構(gòu)體的指針變量),使它們分

9、別指向,n個文件(確切地說指向存放該文件信息的結(jié)構(gòu)體變量),以實現(xiàn)對文件的訪問。 13.3文件的打開與關(guān)閉 和其他高級語言一樣,對文件讀寫之前應(yīng)該“打開”該文件,在使用結(jié)束之后應(yīng)關(guān)閉該文件。 13.3.1文件的打開(fopen函數(shù)) ANSI C規(guī)定了標(biāo)準(zhǔn)輸入輸出函數(shù)庫,用fopen()函數(shù)來實現(xiàn)打開文件。,fopen函數(shù)的調(diào)用方式通常為 FILEfp; fp=fopen(文件名,使用文件方式); 例如: fp=fopen(a1,r); 它表示要打開名字為a1的文件,使用文件方式為“讀入” (r代表read,即讀入),fopen函數(shù)帶回指向a1文件的指針并賦給fp,這樣fp就和文件a1相聯(lián)系了

10、,或者說,fp指向a1文件。可以看出,在打開一個文件時,通知給編譯系統(tǒng)以下3個信息:需要打開的文件名,也就是準(zhǔn)備訪問的文件的名字。,使用文件的方式(“讀”還是“寫”等)。 讓哪一個指針變量指向被打開的文件。 說明: (1) 用“r”方式打開的文件只能用于向計算機(jī)輸入而不能用作向該文件輸出數(shù)據(jù),而且該文件應(yīng)該已經(jīng)存在,不能用“r”方式打開一個并不存在的文件(即輸入文件),否則出錯。 (2) 用“w”方式打開的文件只能用于向該文件寫數(shù)據(jù)(即輸出文件),而不能用來向計算機(jī)輸入。如果原來不存在該文件,則在打開時新建立一個以指定的名字命名的文件。如果原來已存在一個以該文件名命名的文件,則在打開時將該文件

11、刪去,然后重新建立一個新文件。,(3) 如果希望向文件末尾添加新的數(shù)據(jù)(不希望刪除原有數(shù)據(jù)),則應(yīng)該用“a”方式打開。但此時該文件必須已存在,否則將得到出錯信息。打開時,位置指針移到文件末尾。 (4) 用“r+”、“w+”、“a+”方式打開的文件既可以用來輸入數(shù)據(jù),也可以用來輸出數(shù)據(jù)。用“r+”方式時該文件應(yīng)該已經(jīng)存在,以便能向計算機(jī)輸入數(shù)據(jù)。用“w+”方式則新建立一個文件,先向此文件寫數(shù)據(jù),然后可以讀此文件中的數(shù)據(jù)。用“a+”方式打開的文件,原來的文件不被刪去,位置指針移到文件末尾,可以添加,也可以讀。 (5) 如果不能實現(xiàn)“打開”的任務(wù),fopen函數(shù)將會帶回一個出錯信息。出錯的原因可能是

12、用“r”方式,打開一個并不存在的文件;磁盤出故障;磁盤已滿無法建立新文件等。此時fopen函數(shù)將帶回一個空指針值NULL(NULL在stdioh文件中已被定義為0)。 常用下面的方法打開一個文件: if(fp=fopen(file1,r)=NULL) printf(cannot open this filen); exit(0); 即先檢查打開的操作有否出錯,如果有錯就在終端上輸出“cannot open this file”。exit函數(shù)的作用是關(guān)閉所有文件,終止正在調(diào)用的過程。待用戶檢查出錯誤,修改后再運(yùn)行。,(6) 用以上方式可以打開文本文件或二進(jìn)制文件,這是ANSI C的規(guī)定,用同一種

13、緩沖文件系統(tǒng)來處理文本文件和二進(jìn)制文件。但目前使用的有些C編譯系統(tǒng)可能不完全提供所有這些功能(例如有的只能用“r”、“w”、“a”方式),有的C版本不用“r+”、“w+”、“a+”,而用“rw”、“wr”、“ar”等,請讀者注意所用系統(tǒng)的規(guī)定。 (7) 在向計算機(jī)輸入文本文件時,將回車換行符轉(zhuǎn)換為一個換行符,在輸出時把換行符轉(zhuǎn)換成為回車和換行兩個字符。在用二進(jìn)制文件時,不進(jìn)行這種轉(zhuǎn)換,在內(nèi)存中的數(shù)據(jù)形式與輸出到外部文件中的數(shù)據(jù)形式完全一致,一一對應(yīng)。,(8) 在程序開始運(yùn)行時,系統(tǒng)自動打開3個標(biāo)準(zhǔn)文件:標(biāo)準(zhǔn)輸入、標(biāo)準(zhǔn)輸出、標(biāo)準(zhǔn)出錯輸出。通常這3個文件都與終端相聯(lián)系。因此以前我們所用到的從終端輸

14、入或輸出都不需要打開終端文件。系統(tǒng)自動定義了3個文件指針stdin、stdout和stderr,分別指向終端輸入、終端輸出和標(biāo)準(zhǔn)出錯輸?也從終端輸出)。如果程序中指定要從stdin所指的文件輸入數(shù)據(jù),就是指從終端鍵盤輸入數(shù)據(jù)。 13.3.2文件的關(guān)閉(fclose函數(shù)) 在使用完一個文件后應(yīng)該關(guān)閉它,以防止它再被誤用?!瓣P(guān)閉”就是使文件指針變量不指向該文件,,也就是文件指針變量與文件“脫鉤”,此后不能再通過該指針對原來與其相聯(lián)系的文件進(jìn)行讀寫操作。除非再次打開,使該指針變量重新指向該文件。 用fclose函數(shù)關(guān)閉文件。fclose函數(shù)調(diào)用的一般形式為 fclose(文件指針); 例如: fcl

15、ose(fp); 前面我們曾把打開文件(用fopen函數(shù))時所帶回的指針賦給了fp,今通過fp把該文件關(guān)閉。即fp不再指向該文件。,應(yīng)該養(yǎng)成在程序終止之前關(guān)閉所有文件的習(xí)慣,如果不關(guān)閉文件將會丟失數(shù)據(jù)。因為,如前所述,在向文件寫數(shù)據(jù)時,是先將數(shù)據(jù)輸?shù)骄彌_區(qū),待緩沖區(qū)充滿后才正式輸出給文件。如果當(dāng)數(shù)據(jù)未充滿緩沖區(qū)而程序結(jié)束運(yùn)行,就會將緩沖區(qū)中的數(shù)據(jù)丟失。用fclose函數(shù)關(guān)閉文件,可以避免這個問題,它先把緩沖區(qū)中的數(shù)據(jù)輸出到磁盤文件,然后才釋放文件指針變量。 fclose函數(shù)也帶回一個值,當(dāng)順利地執(zhí)行了關(guān)閉操作,則返回值為0;否則返回EOF(-1)。可以用ferror函數(shù)來測試(見13.61節(jié))

16、。,13.4文 件 的 讀 寫 文件打開之后,就可以對它進(jìn)行讀寫了。常用的讀寫函數(shù)如下所述。 13.4.1fputc函數(shù)和fgetc函數(shù)(putc函數(shù)和getc函數(shù)) 1.fputc函數(shù) 把一個字符寫到磁盤文件上去。其一般調(diào)用形式為 fputc(ch,fp); 其中ch是要輸出的字符,它可以是一個字符常量,也可以是一個字符變量。fp是文件指針變量。fputc(ch,fp)函數(shù)的作用是將字符(ch的值)輸出到fp所指向的文件中去。fputc函數(shù)也帶回一個值:,如果輸出成功則返回值就是輸出的字符;如果輸出失敗,則返回一個EOF(-1)。EOF是在stdioh文件中定義的符號常量,值為-1。在第4章

17、介紹過putchar函數(shù),其實putchar是從fputc函數(shù)派生出來的。putchar(c)是在stdio.h文件中用預(yù)處理命令#define定義的宏:#defineputchar(c)fputc(c,stdout)前面已敘述,stdout是系統(tǒng)定義的文件指針變量,它與終端輸出相連。fputc(c瑂tdout)的作用是將c的值輸出到終端。用宏putchar(c)比寫fputc(c,stdout)簡單一些。從用戶的角度,可以把putchar(c)看作函數(shù)而不必嚴(yán)格地稱它為宏。,2. fgetc函數(shù) 從指定的文件讀入一個字符,該文件必須是以讀或讀寫方式打開的。fgetc函數(shù)的調(diào)用形式為 ch=f

18、getc(fp); fp為文件型指針變量,ch為字符變量。fgetc函數(shù)帶回一個字符,賦給ch。如果在執(zhí)行fgetc函數(shù)讀字符時遇到文件結(jié)束符,函數(shù)返回一個文件結(jié)束標(biāo)志EOF(-1)。如果想從一個磁盤文件順序讀入字符并在屏幕上顯示出來,可以:,ch=fgetc(fp); while(ch!=EOF) putchar(ch); ch=fgetc(fp); 注意:EOF不是可輸出字符,因此不能在屏幕上顯示。由于字符的ASCII碼不可能出現(xiàn)-1,因此EOF定義為-1是合適的。當(dāng)讀入的字符值等于-1(即EOF)時,表示讀入的已不是正常的字符而是文件結(jié)束符。但以上只適用于讀文本文件的情況?,F(xiàn)在ANSI

19、C已允許用緩沖文件系統(tǒng)處理二進(jìn)制文件,而讀入某一個字節(jié)中的二進(jìn)制數(shù)據(jù)的值有可能是-1,而這又,恰好是EOF的值。這就出現(xiàn)了需要讀入有用數(shù)據(jù)而卻被處理為“文件結(jié)束”的情況。為了解決這個問題,ANSI C提供一個feof函數(shù)來判斷文件是否真的結(jié)束。feof(fp)用來測試fp所指向的文件當(dāng)前狀態(tài)是否“文件結(jié)束”。如果是文件結(jié)束,函數(shù)feof(fp)的值為1(真),否則為0(假)。 如果想順序讀入一個二進(jìn)制文件中的數(shù)據(jù),可以用 while(!feof(fp) c=fgetc(fp); ,當(dāng)未遇文件結(jié)束,feof(fp)的值為0,!feof(fp)為1,讀入一個字節(jié)的數(shù)據(jù)賦給整型變量c,并接著對其進(jìn)行

20、所需的處理。直到遇文件結(jié)束,feof(fp)值為1,!feof(fp)值為0,不再執(zhí)行while循環(huán)。 這種方法也適用于文本文件。 3. fputc和fgetc函數(shù)使用舉例 在掌握了以上幾種函數(shù)以后,可以編制一些簡單的使用文件的程序。 例13.1從鍵盤輸入一些字符,逐個把它們送到磁盤上去,直到輸入一個“#”為止。,#include main() FILEfp; char ch,filename10; scanf(%s,filename); if(fp=fopen(filename,w)=NULL) printf(cannot open filen); exit(0); ch=getchar(

21、);/*此語句用來接收在執(zhí)行scanf語句時最后輸入的回車符*/ ch=getchar();/*接收輸入的第一個字符*/,while(ch!=#) fputc(ch,fp);putchar(ch); ch=getchar(); fclose(fp); 運(yùn)行情況如下: file1c (輸入磁盤文件名) computer and c#(輸入一個字符串) computer and c (輸出一個字符串),文件名由鍵盤輸入,賦給字符數(shù)組filename,fopen函數(shù)中的第一個參數(shù)“文件名”可以直接寫成字符串常量形式(如“file1c”),也可以用字符數(shù)組名,在字符數(shù)組中存放文件名(如本例所用的方法)

22、。本例運(yùn)行時,從鍵盤輸入磁盤文件名“file1c”,然后輸入要寫入該磁盤文件的字符“computer and c”,“#”是表示輸入結(jié)束,程序?qū)ⅰ癱omputer and c”寫到以“file1c”命名的磁盤文件中,同時在屏幕上顯示這些字符,以便核對。 可以用DOS命令將file1c文件中的內(nèi)容打印出來:Ctype file1c computer and c,證明了在file1c文件中已存入了“computer and c”的信息。 例13.2將一個磁盤文件中的信息復(fù)制到另一個磁盤文件中。 #include main() FILEin,out; char ch,infile10,outfile

23、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 infilen); exit(0); if(out=fopen(outfile,w)=NULL) printf(cannot open outfilen); exit(0);, while(!feof(in)fputc(fgetc(in),out); fclose(in); fclose(

24、out); 運(yùn)行情況如下: Enter the infile name: file1c(輸入原有磁盤文件名) Enter the outfile name: file2c(輸入新復(fù)制的磁盤文件名),程序運(yùn)行結(jié)果是將file1c文件中的內(nèi)容復(fù)制到file2c中去??梢杂孟旅鍰OS命令驗證 ctype file1c computer and c(file1c中的信息) ctype file2c computer and c(file2c中的信息) 以上程序是按文本文件方式處理的。也可以用此程序來復(fù)制一個二進(jìn)制文件,只需將兩個fopen函數(shù)中的“r”和“w”分別改為“rb”和“wb”即可。 也可以在

25、輸入命令行時把兩個文件名一起輸入。這時要用到main函數(shù)的參數(shù)。程序可改為,#include main(int argc,char*argv ) FILEin,*out; char ch; if(argc!=3) printf(You forgot to enter a filenamen); exit(0); if(in=fopen(argv1,r)=NULL) printf(cannot open infilen);,exit(0); if(out=fopen(argv2,w)=NULL) printf(cannot open outfilen); exit(0); while(!feof

26、(in)fputc(fgetc(in),out); fclose(in); fclose(out);, 假若本程序的源文件名為a.c,經(jīng)編譯連接后得到的可執(zhí)行文件名為a.exe,則在DOS命令工作方式下,可以輸入以下的命令行: Cafile1cfile2c 即在鍵入可執(zhí)行文件名后,再輸入兩個參數(shù)file1c和file2c,分別輸入到argv1和argv2中,argv0的內(nèi)容為a,argc的值等于3(因為此命令行共有3個參數(shù))。如果輸入的參數(shù)少于3個,則程序會輸出:“你忘了輸入一個文件名”。程序執(zhí)行結(jié)果是將file1c中的信息復(fù)制到file2c中??梢杂靡韵旅铗炞C:,Ctype file1c

27、computer and c (這是file1c文件中的信息) Ctype file2c computer and c (這是file2c文件中的信息。可見file1c已復(fù)制到file2c中了)。 最后說明一點,為了書寫方便,系統(tǒng)把fputc和fgetc定義為宏名putc和getc: #define putc(ch,fp) fputc(ch,fp) #define getc(fp) fgetc(fp),這是在stdioh中定義的。因此,用putc和fputc及用getc和fgetc是一樣的。一般可以把它們作為相同的函數(shù)來對待。 13.4.2fread函數(shù)和fwrite函數(shù) 用getc和putc

28、函數(shù)可以用來讀寫文件中的一個字符。但是常常要求一次讀入一組數(shù)據(jù)(例如,一個實數(shù)或一個結(jié)構(gòu)體變量的值),ANSI C標(biāo)準(zhǔn)提出設(shè)置兩個函數(shù)(fread和fwrite),用來讀寫一個數(shù)據(jù)塊。它們的一般調(diào)用形式為 fread(buffer,sie,count,fp); fwrite(buffer,sie,count,fp);,其中: buffer:是一個指針。對fread來說,它是讀入數(shù)據(jù)的存放地址。對fwrite來說,是要輸出數(shù)據(jù)的地址(以上指的是起始地址)。 size:要讀寫的字節(jié)數(shù)。 count:要進(jìn)行讀寫多少個sie字節(jié)的數(shù)據(jù)項。 fp:文件型指針。 如果文件以二進(jìn)制形式打開,用fread和f

29、write函數(shù)就可以讀寫任何類型的信息,如: fread(f,4,2,fp); 其中f是一個實型數(shù)組名。一個實型變量占4個字節(jié)。,這個函數(shù)從fp所指向的文件讀入2次(每次4個字節(jié))數(shù)據(jù),存儲到數(shù)組f中。 如果有一個如下的結(jié)構(gòu)體類型: structstudent-type char name10; int num; int age; charaddr30; stud40; 結(jié)構(gòu)體數(shù)組stud有40個元素,每一個元素用來存放一個學(xué)生的數(shù)據(jù)(包括姓名、學(xué)號、年齡、地址)。,假設(shè)學(xué)生的數(shù)據(jù)已存放在磁盤文件中,可以用下面的for語句和fread函數(shù)讀入40個學(xué)生的數(shù)據(jù): for(i=0;i40;i+)

30、fread( 如果fread或fwrite調(diào)用成功,則函數(shù)返回值為count的值,即輸入或輸出數(shù)據(jù)項的完整個數(shù)。,下面寫出一個完整的程序。 例13.3從鍵盤輸入4個學(xué)生的有關(guān)數(shù)據(jù),然后把它們轉(zhuǎn)存到磁盤文件上去。 #include #define SIZE 4 struct student-type char name10; int num; int age; char addr15;,studSIZE; void save() FILEfp; int i; if(fp=fopen(stu-list,wb)=NULL) printf(cannot open filen); return; for

31、(i=0;iSIZE;i+),if(fwrite(,save(); 在main函數(shù)中,從終端鍵盤輸入4個學(xué)生的數(shù)據(jù),然后調(diào)用save函數(shù),將這些數(shù)據(jù)輸出到以“stu_list”命名的磁盤文件中。fwrite函數(shù)的作用是將一個長度為29字節(jié)的數(shù)據(jù)塊送到stu_list文件中(一個student_type類型結(jié)構(gòu)體變量的長度為它的成員長度之和,即10+2+2+15=29)。運(yùn)行情況如下: 輸入4個學(xué)生的姓名、學(xué)號、年齡和地址: Zhang100119room-101,Fun 1002 20 room-102 Tan 1003 21 room-103 Ling 1004 21 room-104 程序

32、運(yùn)行時,屏幕上并無輸出任何信息,只是將從鍵盤輸入的數(shù)據(jù)送到磁盤文件上。為了驗證在磁盤文件“stu_list”中是否已存在此數(shù)據(jù)可以用以下程序從“stu_list”文件中讀入數(shù)據(jù),然后在屏幕上輸出。 #include #define SIZE 4 struct student-type,char name10; int num; int age; char addr15; studSIZE; main() int i; FILEfp; fp=fopen(stu-list,rb); for(i=0;iSIZE;i+),fread( 程序運(yùn)行時不需從鍵盤輸入任何數(shù)據(jù)。屏幕上顯示出以下信息: Zhan

33、g100119room-101 Fun 1002 20 room-102,Tan 1003 21 room-103 Ling 1004 21 room-104 請注意輸入輸出數(shù)據(jù)的狀況。從鍵盤輸入4個學(xué)生的數(shù)據(jù)是ASCII碼,也就是文本文件。在送到計算機(jī)內(nèi)存時,回車和換行符轉(zhuǎn)換成一個換行符。再從內(nèi)存以“wb”方式 (二進(jìn)制寫)輸出到“stu_list”文件,此時不發(fā)生字符轉(zhuǎn)換,按內(nèi)存中存儲形式原樣輸出到磁盤文件上。在上面驗證程序中,又用fread函數(shù)從“stu_list”文件向內(nèi)存讀入數(shù)據(jù),注意此時用的是“rb”方式,即二進(jìn)制方式,數(shù)據(jù)按原樣輸入,也不發(fā)生字符轉(zhuǎn)換。也就是這時候內(nèi)存中的數(shù)據(jù)恢復(fù)

34、到第一個程序向,“stu-list”輸出以前的情況。最后在驗證程序中,用printf函數(shù)輸出到屏幕,printf是格式輸出函數(shù),輸出ASCII碼,在屏幕上顯示字符。換行符又轉(zhuǎn)換為回車加換行符。 如果企圖從“stu_list”文件中以“r”方式讀入數(shù)據(jù)就會出錯。 fread和fwrite函數(shù)一般用于二進(jìn)制文件的輸入輸出。因為它們是按數(shù)據(jù)塊的長度來處理輸入輸出的,在字符發(fā)生轉(zhuǎn)換的情況下很可能出現(xiàn)與原設(shè)想的情況不同。 例如,如果寫fread(,企圖從終端鍵盤輸入數(shù)據(jù),這在語法上并不存在錯誤,編譯能通過。如果用以下形式輸入數(shù)據(jù): Zhang 100110room-101 由于fread函數(shù)要求一次輸入

35、29個字節(jié)(而不問這些字節(jié)的內(nèi)容),因此輸入數(shù)據(jù)中的空格也作為輸入數(shù)據(jù)而不作為數(shù)據(jù)間的分隔符了。連空格也存儲到studi中了,顯然是不對的。 這個題目要求的是從鍵盤輸入數(shù)據(jù),如果已有的數(shù)據(jù)已以二進(jìn)制形式存儲在一個磁盤文件“stu-dat”中,要求從其中讀入數(shù)據(jù)并輸出到“stu-list”文件中,可以編寫一個load函數(shù),從磁盤文件中讀,二進(jìn)制數(shù)據(jù)。 void load() FILEfp; int i; if(fp=fopen(stu-dat,rb)=NULL) printf(cannot open infilen); return; for(i=0;iSIZE;i+) if(fread( re

36、turn; printf(file read errorn); fclose (fp); 將load函數(shù)加到本題原來的程序文件中,并將main函數(shù)改為main() load(); save(); ,13.4.3fprintf函數(shù)和fscanf函數(shù) fprintf函數(shù)、fscanf函數(shù)與printf函數(shù)、scanf函數(shù)作用相仿,都是格式化讀寫函數(shù)。只有一點不同:fprintf和fscanf函數(shù)的讀寫對象不是終端而是磁盤文件。它們的一般調(diào)用方式為fprintf(文件指針,格式字符串,輸出表列);fscanf (文件指針,格式字符串,輸入表列);例如: fprintf(fp,%d,%62f,i,t)

37、; 它的作用是將整型變量i和實型變量t的值按%d和%62f的格式輸出到fp指向的文件上。如果i=3,t=45,則輸出到磁盤文件上的是以下的字符串:,3,450 同樣,用以下fscanf函數(shù)可以從磁盤文件上讀入ASCII字符:fscanf(fp,%d,%f, 磁盤文件上如果有以下字符: 3,45 則將磁盤文件中的數(shù)據(jù)3送給變量i,45送給變量t。 用fprintf和fscanf函數(shù)對磁盤文件讀寫,使用方便,容易理解,但由于在輸入時要將ASCII碼轉(zhuǎn)換為二進(jìn)制形式,在輸出時又要將二進(jìn)制形式轉(zhuǎn)換成字符,花費時間比較多。因此,在內(nèi)存與磁盤頻繁交換數(shù)據(jù)的情況下,最好不用fprintf和,fscanf函數(shù)

38、,而用fread和fwrite函數(shù)。 13.4.4其他讀寫函數(shù) 1. putw和getw函數(shù) 大多數(shù)C編譯系統(tǒng)都提供另外兩個函數(shù):putw和getw,用來對磁盤文件讀寫一個字(整數(shù))。例如: putw(10,fp); 它的作用是將整數(shù)10輸出到fp指向的文件。而i=getw(fp);的作用是從磁盤文件讀一個整數(shù)到內(nèi)存,賦給整型變量i。 如果所用的C編譯的庫函數(shù)中不包括putw和getw函數(shù),可以自己定義該兩函數(shù)。putw函數(shù)如下:,putw(int i,F(xiàn)ILE *fp) chars; s=(char*)”語句,形參i得到實參傳來的值10,在putw函數(shù)中將i的地址賦予指針變量s,而s是指向字

39、符變量的指針變量,因此s指向i的第1個字節(jié),s+1指向i的第2個字節(jié)。由于*(s+0)就是s0,*(s+1)就是s1,因此,s0、s1分別對應(yīng)i的第1字節(jié)和第2個字節(jié)。由于,圖13.3,*(s+0)就是s0,*(s+1)就是s1,因此,s0、s1分別對應(yīng)i的第1字節(jié)和第2字節(jié)。順序輸出s0、s1就相當(dāng)于輸出了i的兩個字節(jié)中的內(nèi)容。見圖13.3。,getw函數(shù)如下: getw(FILE *fp) chars; int i; s=(char *) putw和getw并不是ANSI C標(biāo)準(zhǔn)定義的函數(shù)。但許多C編譯都提供這兩個函數(shù),但有的C編譯可能不,以putw和getw命名此兩函數(shù),而用其他函數(shù)名,

40、請用時注意。 2. 讀寫其他類型數(shù)據(jù) 如果用ANSI C提供的fread和fwrite函數(shù),讀寫任何類型數(shù)據(jù)都是十分方便的。如果所用的系統(tǒng)不提供這兩個函數(shù),用戶只好自己定義所需函數(shù)。例如,可以定義一個向磁盤文件寫一個實數(shù)(用二進(jìn)制方式)的函數(shù)putfloat: putfloat(float num,F(xiàn)ILE *fp) chars;,int count; s=(char *) n為要求得到的字符,但只從fp指向的文件輸入n-1個字符,然后在最后加一個0字符,因此得到,的字符串共有n個字符。把它們放到字符數(shù)組str中。如果在讀完n-1個字符之前遇到換行符或EOF,讀入即結(jié)束。fgets函數(shù)返回值為

41、str的首地址。 fputs函數(shù)的作用是向指定的文件輸出一個字符串。如:fputs(China,fp);把字符串“China”輸出到fp指向的文件。fputs函數(shù)中第一個參數(shù)可以是字符串常量、字符數(shù)組名或字符型指針。字符串末尾的0 不輸出。若輸出成功,函數(shù)值為0;失敗時,為EOF。 這兩個函數(shù)類似以前介紹過的gets和puts函數(shù),只是fgets和fputs函數(shù)以指定的文件作為讀寫對象。,13.5文 件 的 定 位 文件中有一個位置指針,指向當(dāng)前讀寫的位置。如果順序讀寫一個文件,每次讀寫一個字符,則讀寫完一個字符后,該位置指針自動移動指向下一個字符位置。如果想改變這樣的規(guī)律,強(qiáng)制使位置指針指向

42、其他指定的位置,可以用有關(guān)函數(shù)。 13.5.1rewind函數(shù) rewind函數(shù)的作用是使位置指針重新返回文件的開頭。此函數(shù)沒有返回值。 例13.4有一個磁盤文件,第一次將它的內(nèi)容顯示在屏幕上,第二次把它復(fù)制到另一文件上。,#include main() FILEfp1,*fp2; fp1=fopen(file1c,r); fp2=fopen(file2c,w); while(!feof(fp1)putchar(getc(fp1); rewind(fp1); while(!feof(fp1)putc(getc(fp1),fp2); fclose(fp1);fclose(fp2); 在第一次將文

43、件的內(nèi)容顯示在屏幕以后,文件file1c的位置指針已指到文件末尾,feof的值為非零(真)。執(zhí)行rewind函數(shù),使文件的位置指針重,新定位于文件開頭,并使feof函數(shù)的值恢復(fù)為0(假)。 13.5.2fseek函數(shù)和隨機(jī)讀寫 對流式文件可以進(jìn)行順序讀寫,也可以進(jìn)行隨機(jī)讀寫。關(guān)鍵在于控制文件的位置指針,如果位置指針是按字節(jié)位置順序移動的,就是順序讀寫。如果能將位置指針按需要移動到任意位置,就可以實現(xiàn)隨機(jī)讀寫。所謂隨機(jī)讀寫,是指讀寫完上一個字符(字節(jié))后,并不一定要讀寫其后續(xù)的址?字節(jié)),而可以讀寫文件中任意所需的字符(字節(jié))。 用fseek函數(shù)可以實現(xiàn)改變文件的位置指針。,fseek函數(shù)的調(diào)用

44、形式為fseek(文件類型指針,位移量,起始點) “起始點”用0、1或2代替,0代表“文件開始”,1為“當(dāng)前位置”,2為“文件末尾”。ANSI C標(biāo)準(zhǔn)指定的名字如表13.2所示。 “位移量”指以“起始點”為基點,向前移動的字節(jié)數(shù)。ANSI C和大多數(shù)C版本要求位移量是long型數(shù)據(jù)。這樣當(dāng)文件的長度大于64時不致出問題。ANSI C標(biāo)準(zhǔn)規(guī)定在數(shù)字的末尾加一個字母L,就表示是long型。 下面是fseek函數(shù)調(diào)用的幾個例子: fseek(fp,100L,0);將位置指針移到離文件頭100個字節(jié)處,fseek(fp,50L,1); 將位置指針移到離當(dāng)前位置50個字節(jié)處 fseek(fp,-10L,2); 將位置指針從文件末尾處向后退10個字節(jié) 利用fseek函數(shù)就可以實現(xiàn)隨機(jī)讀寫了。 例13.5在磁盤文件上存有10個學(xué)生的數(shù)據(jù)。要求將第1、3、5、7、9個學(xué)生數(shù)據(jù)輸入計算機(jī),并在屏幕上顯示出來。 程序如下: #include,struct student-type char name10; int num; int age; char sex; stud10; main() int i; FILE *fp;,if(fp=fopen(stud -dat,rb)=NULL) printf(can not open filen); exit(0); for(i=0;i1

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

最新文檔

評論

0/150

提交評論