《程序設(shè)計(jì)基礎(chǔ)》課件第10章_第1頁
《程序設(shè)計(jì)基礎(chǔ)》課件第10章_第2頁
《程序設(shè)計(jì)基礎(chǔ)》課件第10章_第3頁
《程序設(shè)計(jì)基礎(chǔ)》課件第10章_第4頁
《程序設(shè)計(jì)基礎(chǔ)》課件第10章_第5頁
已閱讀5頁,還剩68頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

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

文檔簡(jiǎn)介

第10章文件10.1文件概述

10.2文件的讀寫

10.3文件定位

習(xí)題

10.1文件概述

文件(file)是程序設(shè)計(jì)中一個(gè)重要的概念。所謂“文件”,一般指存儲(chǔ)在外部介質(zhì)上數(shù)據(jù)的集合。一批數(shù)據(jù)是以文件的形式存放在外部介質(zhì)(如磁盤)上的。操作系統(tǒng)是以文件為單位對(duì)數(shù)據(jù)進(jìn)行管理的,也就是說,如果想找存在外部介質(zhì)上的數(shù)據(jù),必須先按文件名找到所指定的文件,然后再從該文件中讀取數(shù)據(jù)。要向外部介質(zhì)上存儲(chǔ)數(shù)據(jù),也必須先建立一個(gè)文件(以文件名標(biāo)識(shí)),才能向它輸出數(shù)據(jù)。以前各章中所用到的輸入和輸出都是以終端為對(duì)象的,即從鍵盤輸入數(shù)據(jù),運(yùn)行結(jié)果輸出到顯示屏上。從操作系統(tǒng)的角度看,每一個(gè)與主機(jī)相連的輸入/輸出設(shè)備都可看做是一個(gè)文件。例如,終端鍵盤是輸入文件,顯示屏和打印機(jī)是輸出文件。

在程序運(yùn)行時(shí),常常需要將一些數(shù)據(jù)(運(yùn)行的最終結(jié)果或中間數(shù)據(jù))輸出到磁盤上存放起來,以后需要時(shí)再從磁盤中輸入到計(jì)算機(jī)內(nèi)存。這就要用到磁盤文件。

C語言把文件看做是一個(gè)字符(字節(jié))的序列,即由一個(gè)一個(gè)字符(字節(jié))的數(shù)據(jù)順序組成的。根據(jù)數(shù)據(jù)的組織形式,文件可分為ASCII文件和二進(jìn)制文件。ASCII文件又稱文本(text)文件,它的每一個(gè)字節(jié)放一個(gè)ASCII代碼,代表一個(gè)字符。二進(jìn)制文件是把內(nèi)存中的數(shù)據(jù)按其在內(nèi)存中的存儲(chǔ)形式原樣輸出到磁盤上存放。有一個(gè)整數(shù)10000,在內(nèi)存中占2個(gè)字節(jié),如果按ASCII碼形式輸出,則占5個(gè)字節(jié),而按二進(jìn)制形式輸出,在磁盤上只占2個(gè)字節(jié),見圖10-1。用ASCII碼形式輸出與字符一一對(duì)應(yīng),一個(gè)字節(jié)代表一個(gè)字符,因而便于對(duì)字符進(jìn)行逐個(gè)處理,也便于輸出字符,但一般占存儲(chǔ)空間較多,而且要花費(fèi)轉(zhuǎn)換時(shí)間(二進(jìn)制形式與ASCII碼間的轉(zhuǎn)換)。用二進(jìn)制形式輸出數(shù)值,可以節(jié)省外存空間和轉(zhuǎn)換時(shí)間,但一個(gè)字節(jié)并不對(duì)應(yīng)一個(gè)字符,不能直接輸出字符形式。一般中間結(jié)果數(shù)據(jù)需要暫時(shí)保存在外存上,以后又需要輸入到內(nèi)存的,常用二進(jìn)制文件保存。圖10-1數(shù)據(jù)的存儲(chǔ)形式由前所述,一個(gè)C文件是一個(gè)字節(jié)流或二進(jìn)制流。它把數(shù)據(jù)看作是一連串的字符(字節(jié)),而不考慮記錄的界限。換句話說,C語言中文件并不是由記錄(record)組成的(這是和Pascal或其他高級(jí)語言不同的)。在C語言中對(duì)文件的存取是以字符(字節(jié))為單位的。輸入/輸出的數(shù)據(jù)流的開始和結(jié)束僅受程序控制,而不受物理符號(hào)(如回車換行符)控制。也就是說,在輸出時(shí)不會(huì)自動(dòng)增加回車換行符以作為記錄結(jié)束的標(biāo)志,輸入時(shí)不以回車換行符作為記錄的間隔(事實(shí)上C文件并不由記錄構(gòu)成)。我們把這種文件稱為流式文件。C語言允許對(duì)文件存取一個(gè)字符,這就增加了處理的靈活性。在過去使用的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ū)后才一起送到磁盤去。如果從磁盤向內(nèi)存讀入數(shù)據(jù),則一次從磁盤文件將一批數(shù)據(jù)輸入到內(nèi)存緩沖區(qū)(充滿緩沖區(qū)),然后再從緩沖區(qū)逐個(gè)地將數(shù)據(jù)送到程序數(shù)據(jù)區(qū)(給程序變量)。緩沖文件系統(tǒng)如圖10-2所示。緩沖區(qū)的大小由各個(gè)具體的C版本確定,一般為512字節(jié)。圖10-2緩沖文件系統(tǒng)示意圖所謂“非緩沖文件系統(tǒng)”是指系統(tǒng)不自動(dòng)開辟確定大小的緩沖區(qū),而由程序?yàn)槊總€(gè)文件設(shè)定緩沖區(qū)。

在UNIX系統(tǒng)下,用緩沖文件系統(tǒng)來處理文本文件,用非緩沖文件系統(tǒng)處理二進(jìn)制文件。用緩沖文件系統(tǒng)進(jìn)行的輸入/輸出又稱為高級(jí)(或高層)磁盤輸入/輸出(高層I/O),用非緩沖文件系統(tǒng)進(jìn)行的輸入/輸出又稱為低級(jí)(低層)輸入/輸出。ANSIC標(biāo)準(zhǔn)規(guī)定不采用非緩沖文件系統(tǒng),而只采用緩沖文件系統(tǒng),即用緩沖文件系統(tǒng)處理文本文件,也用它來處理二進(jìn)制文件,也就是將緩沖文件系統(tǒng)擴(kuò)充為可以處理二進(jìn)制文件。在C語言中,沒有輸入/輸出語句,對(duì)文件的讀寫都是用庫函數(shù)來實(shí)現(xiàn)的。ANSI規(guī)定了標(biāo)準(zhǔn)輸入/輸出函數(shù),可用它們對(duì)文件進(jìn)行讀寫。

本章只介紹ANSIC規(guī)定的文件系統(tǒng)以及對(duì)它的讀寫。

10.1.1文件和文件指針

緩沖文件系統(tǒng)中,關(guān)鍵的概念是“文件指針”。每個(gè)被使用的文件都在內(nèi)存中開辟一個(gè)區(qū),用來存放文件的有關(guān)信息(如文件的名字、文件狀態(tài)及文件當(dāng)前位置等)。這些信息是保存在一個(gè)結(jié)構(gòu)體變量中的。該結(jié)構(gòu)體類型是由系統(tǒng)定義的,取名為FILE。TurboC在stdio.h文件中有以下的文件類型聲明:typedef

struct

{

shortlevel; /*緩沖區(qū)“滿”或“空”的程度*/

unsignedflags; /*文件狀態(tài)標(biāo)志*/

charfd;

/*文件描述符*/

unsignedcharhold; /*如無緩沖區(qū)則不讀取字符*/

shortbsize;

/*緩沖區(qū)的大小*/

unsignedchar*buffer; /*數(shù)據(jù)緩沖區(qū)的位置*/

unsignedar*curp; /*指針,當(dāng)前的指向*/

unsignedistemp; /*臨時(shí)文件,指示器*/

shorttoken; /*用于有效性檢查*/

}FILE;有了結(jié)構(gòu)體FILE類型之后,就可以用它來定義若干個(gè)FILE類型的變量,以便存放若干個(gè)文件的信息。例如,可以定義以下FILE類型的數(shù)組:

FILE

f[5];

定義了一個(gè)結(jié)構(gòu)體數(shù)組f,它有5個(gè)元素,可以用來存放5個(gè)文件的信息。

可以定義文件型指針變量。如:

FILE*fp;

fp是一個(gè)指向FILE類型結(jié)構(gòu)體的指針變量。可以使fp指向某一個(gè)文件的結(jié)構(gòu)體變量,從而通過該結(jié)構(gòu)體變量中的文件信息能夠訪問該文件。也就是說,通過文件指針變量能夠找到與它相關(guān)的文件。如果有n個(gè)文件,一般應(yīng)設(shè)n個(gè)指針變量(指向FILE類型結(jié)構(gòu)體的指針變量),使它們分別指向n個(gè)文件(確切地說,是指向存放該文件信息的結(jié)構(gòu)體變量),以實(shí)現(xiàn)對(duì)文件的訪問。注意:

(1)由于文件類型FILE在頭文件stdio.h中定義,所以在使用FILE類型前必須先打開stdio.h文件。

(2)如果需要對(duì)某一個(gè)文件進(jìn)行讀寫操作,則必須首先指定指向它的文件指針。只有通過文件指針,才能調(diào)用相應(yīng)的文件。當(dāng)程序需要同時(shí)處理多個(gè)文件時(shí),則需要說明多個(gè)FILE型的指針變量,使它們分別指向多個(gè)不同的文件。10.1.2文件操作的一般過程

使用文件的一般步驟如下:打開文件→操作文件→關(guān)閉文件。

(1)打開文件:建立用戶程序與文件的聯(lián)系,系統(tǒng)為文件開辟文件緩沖區(qū)。

(2)操作文件:是指對(duì)文件的讀、寫、追加和定位操作。

①讀操作:從文件中讀出數(shù)據(jù),即將文件中的數(shù)據(jù)輸入到計(jì)算機(jī)內(nèi)存。

②寫操作:向文件中寫入數(shù)據(jù),即將計(jì)算機(jī)內(nèi)存中的數(shù)據(jù)輸出到文件。③追加操作:將新的數(shù)據(jù)寫到文件原有數(shù)據(jù)的后面。

④定位操作:移動(dòng)文件讀寫位置指針。

(3)關(guān)閉文件:切斷文件與程序的聯(lián)系,將文件緩沖區(qū)的內(nèi)容寫入磁盤,并釋放文件緩沖區(qū)。10.1.3文件的打開與關(guān)閉

和其他高級(jí)語言一樣,對(duì)文件讀寫之前應(yīng)該“打開”該文件,在使用結(jié)束之后應(yīng)關(guān)閉該文件。

1.文件的打開(fopen函數(shù))

ANSIC規(guī)定了標(biāo)準(zhǔn)輸入/輸出函數(shù)庫,用fopen(

)函數(shù)來實(shí)現(xiàn)打開文件。

fopen函數(shù)的調(diào)用方式通常為:

FILE*fp;

fp=fopen(文件名,使用文件方式);

例如:

fp=fopen("a1","r");它表示要打開名字為a1的文件,使用文件方式為“讀入”(r代表read,即讀入)。fopen函數(shù)帶回指向a1文件的指針并賦給fp,這樣fp就和文件a1相聯(lián)系了,或者說,fp指向a1文件??梢钥闯?,在打開一個(gè)文件時(shí),通知給編譯系統(tǒng)以下3個(gè)信息:

①需要打開的文件名,也就是準(zhǔn)備訪問的文件的名字。

②使用文件的方式(“讀”還是“寫”等)。

③讓哪一個(gè)指針變量指向被打開的文件。說明:

(1)用“r”方式打開的文件只能用于向計(jì)算機(jī)輸入而不能用作向該文件輸出數(shù)據(jù),而且該文件應(yīng)該已經(jīng)存在。不能用“r”方式打開一個(gè)并不存在的文件(即輸入文件),否則出錯(cuò)。

(2)用“w”方式打開的文件只能用于向該文件寫數(shù)據(jù)(即輸出文件),而不能用來向計(jì)算機(jī)輸入。如果原來不存在該文件,則在打開時(shí)新建立一個(gè)以指定的名字命名的文件。如果原來已存在一個(gè)以該文件名命名的文件,則在打開時(shí)將該文件刪去,然后重新建立一個(gè)新文件。

(3)如果希望向文件末尾添加新的數(shù)據(jù)(不希望刪除原有數(shù)據(jù)),則應(yīng)該用“a”方式打開。但此時(shí)該文件必須已存在,否則將得到出錯(cuò)信息。打開時(shí),位置指針移到文件末尾。

(4)用“r+”、“w+”、“a+”方式打開的文件既可以用來輸入數(shù)據(jù),也可以用來輸出數(shù)據(jù)。用“r+”方式時(shí),該文件應(yīng)該已經(jīng)存在,以便能向計(jì)算機(jī)輸入數(shù)據(jù);用“w+”方式則新建立一個(gè)文件,先向此文件寫數(shù)據(jù),然后可以讀此文件中的數(shù)據(jù);用“a+”方式打開的文件,原來的文件不被刪去,位置指針移到文件末尾,可以添加,也可以讀。

(5)如果不能實(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("file1","r"))==NULL)

{

printf("cannotopenthisfile\n");

exit(0);

}即先檢查打開的操作有否出錯(cuò),如果有錯(cuò)就在終端上輸出“cannotopenthisfile”。exit函數(shù)的作用是關(guān)閉所有文件,終止正在調(diào)用的過程。待用戶檢查出錯(cuò)誤,修改后再運(yùn)行。

(6)用以上方式可以打開文本文件或二進(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ī)定。

(7)在向計(jì)算機(jī)輸入文本文件時(shí),將回車換行符轉(zhuǎn)換為一個(gè)換行符;在輸出時(shí),把換行符轉(zhuǎn)換成為回車和換行兩個(gè)字符。在用二進(jìn)制文件時(shí),不進(jìn)行這種轉(zhuǎn)換,在內(nèi)存中的數(shù)據(jù)形式與輸出到外部文件中的數(shù)據(jù)形式完全一致,一一對(duì)應(yīng)。

(8)在程序開始運(yùn)行時(shí),系統(tǒng)自動(dòng)打開3個(gè)標(biāo)準(zhǔn)文件:標(biāo)準(zhǔn)輸入、標(biāo)準(zhǔn)輸出、標(biāo)準(zhǔn)出錯(cuò)輸出。通常這3個(gè)文件都與終端相聯(lián)系。因此以前所用到的從終端輸入或輸出都不需要打開終端文件。系統(tǒng)自動(dòng)定義了3個(gè)文件指針stdin、stdout和stderr,分別指向終端輸入、終端輸出和標(biāo)準(zhǔn)出錯(cuò)輸出(也從終端輸出)。如果程序中指定要從stdin所指的文件輸入數(shù)據(jù),就是指從終端鍵盤輸入數(shù)據(jù)。

2.文件的關(guān)閉(fclose函數(shù))

在使用完一個(gè)文件后應(yīng)該關(guān)閉它,以避免數(shù)據(jù)丟失?!瓣P(guān)閉”就是使文件指針變量不指向該文件,也就是文件指針變量與文件“脫鉤”,此后不能再通過該指針對(duì)原來與其相聯(lián)系的文件進(jìn)行讀寫操作。(除非再次打開,使該指針變量重新指向該文件。)用fclose函數(shù)關(guān)閉文件。fclose函數(shù)調(diào)用的一般形式為:

fclose(文件指針);

例如:

fclose(fp);前面曾把打開文件(用fopen函數(shù))時(shí)所帶回的指針賦給了fp,現(xiàn)在通過fp把該文件關(guān)閉。即fp不再指向該文件。

應(yīng)該養(yǎng)成在程序終止之前關(guān)閉所有文件的習(xí)慣,如果不關(guān)閉文件將會(huì)引起數(shù)據(jù)丟失。如前所述,在向文件寫數(shù)據(jù)時(shí),是先將數(shù)據(jù)輸?shù)骄彌_區(qū),待緩沖區(qū)充滿后才正式輸出給文件。如果當(dāng)數(shù)據(jù)未充滿緩沖區(qū)而程序結(jié)束運(yùn)行,就會(huì)將緩沖區(qū)中的數(shù)據(jù)丟失。用fclose函數(shù)關(guān)閉文件,可以避免這個(gè)問題,它先把緩沖區(qū)中的數(shù)據(jù)輸出到磁盤文件,然后才釋放文件指針變量。

fclose函數(shù)也帶回一個(gè)值,當(dāng)順利地執(zhí)行了關(guān)閉操作,則返回值為0;否則返回EOF(-1)。可以用ferror函數(shù)來進(jìn)行測(cè)試。 10.2文?件?的?讀?寫

10.2.1fprintf和fscanf函數(shù)

fprintf函數(shù)、fscanf函數(shù)與printf函數(shù)、scanf函數(shù)作用相仿,都是格式化讀寫函數(shù)。只有一點(diǎn)不同:fprintf和fscanf函數(shù)的讀寫對(duì)象不是終端而是磁盤文件。它們的一般調(diào)用方

式為:

fprintf(文件指針,格式字符串,輸出表列);

fscanf(文件指針,格式字符串,輸入表列);例如:

fprintf(fp,"%d,%6.2f",i,t);

它的作用是將整型變量i和實(shí)型變量t的值按%d和%6.2f的格式輸出到fp指向的文件上。如果i=3,t=4.5,則輸出到磁盤文件上的是以下的字符串:

3,4.50

同樣,用以下fscanf函數(shù)可以從磁盤文件上讀入ASCII字符:

fscanf(fp,"%d,%f",&i,&t);磁盤文件上如果有以下字符:

3,4.5

則將磁盤文件中的數(shù)據(jù)3送給變量i,4.5送給變量t。

用fprintf和fscanf函數(shù)對(duì)磁盤文件讀寫,使用方便,容易理解,但由于在輸入時(shí)要將ASCII碼轉(zhuǎn)換為二進(jìn)制形式,在輸出時(shí)又要將二進(jìn)制形式轉(zhuǎn)換成字符,花費(fèi)時(shí)間比較多,因此,?在內(nèi)存與磁盤頻繁交換數(shù)據(jù)的情況下,最好不用fprintf和fscanf函數(shù),而用fread和fwrite函數(shù)。10.2.2fputc和fgetc函數(shù)

1.fputc函數(shù)

fputc函數(shù)把一個(gè)字符寫到磁盤文件上去。其一般調(diào)用形式為:

fputc(ch,fp);

其中ch是要輸出的字符,它可以是一個(gè)字符常量,也可以是一個(gè)字符變量。fp是文件指針變量。fputc(ch,fp)函數(shù)的作用是將字符(ch的值)輸出到fp所指向的文件中去。

fputc函數(shù)也帶回一個(gè)值:如果輸出成功,則返回值就是輸出的字符;如果輸出失敗,則返回一個(gè)EOF(-1)。EOF是在stdio.h文件中定義的符號(hào)常量,其值為?-1。在第4章介紹過putchar函數(shù),其實(shí)putchar是從fputc函數(shù)派生出來的。putchar(c)是在stdio.h文件中用預(yù)處理命令#define定義的宏:

#define

putchar(c)

fputc(c,stdout)

前面已敘述,stdout是系統(tǒng)定義的文件指針變量,它與終端輸出相連。fputc(ch,stdout)的作用是將c的值輸出到終端。用宏putchar(c)比寫fputc(c,stdout)簡(jiǎn)單一些。從用戶的角度,可以把putchar(c)看做函數(shù),而不必嚴(yán)格地稱它為宏。#include"stdio.h"

voidmain()

{

char*p="Thisisaexample.";

while(*p!='\0')

fputc(*p++,stdout);

}

2.fgetc函數(shù)

fgetc函數(shù)從指定文件讀入一個(gè)字符,該文件必須是以讀或讀寫方式打開的。

通常使用如下的形式調(diào)用fgetc()函數(shù):

ch=fgetc(fp);

其中,fp為文件型指針變量,ch為字符變量。正常情況下,fgetc()函數(shù)的返回值是從文件中讀出的一個(gè)字符。當(dāng)打開文件并立即使用fgetc()讀文件時(shí),fgetc()函數(shù)從文件開始位置讀取一個(gè)字符。每讀取一個(gè)字符后,文件的位置指針后移一個(gè)字符位置。若當(dāng)前讀取的是文本文件,則當(dāng)遇到文件結(jié)束標(biāo)志時(shí),fgetc()函數(shù)的返回值為EOF。在編寫程序時(shí),經(jīng)常使用該返回值作為讀取文件字符的控制條件。例如使用fgetc()函數(shù)輸出程序e10-2.c的程序清單:#include"stdio.h"

main()

{

charch;

FILE*fp;

fp=fopen("e10-2.c","r");

while((ch=fgetc(fp))!=EOF)

putchar(ch);

fclose(fp);

}例10-1

把一個(gè)文本文件的內(nèi)容復(fù)制到另一個(gè)文本文件中。

/*源程序10-1*/

#include"stdio.h"

main()

{

charch,source[20],target[20];

FILE*fp_s,*fp_t;

printf("Enterthesourcefilename:");

scanf("%s",source);

printf("Enterthetargetfilename:");

scanf("%s",target);

if((fp_s=fopen(source,"r"))==NULL){

printf("cannotopensourcefile.\n");

exit(1);

}

if((fp_t=fopen(target,"w"))==NULL)

{

printf("cannotopentargetfile.\n");

exit(1);

}

while(!feof(fp_s))

fputc(fgetc(fp_s),fp_t);

fclose(fp_s);

fclose(fp_t);

}10.2.3fputs和fgets函數(shù)

fgets的作用是從指定文件讀入一個(gè)字符串,如:

fgets(str,n,fp);

其中,n為要求得到的字符,但只從fp指向的文件輸入n-1個(gè)字符,然后在最后加一個(gè)'\0'字符,因此得到的字符串共有n個(gè)字符。把它們放到字符數(shù)組str中。如果在讀完n-1個(gè)字符之前遇到換行符或EOF,讀入即結(jié)束。fgets函數(shù)返回值為str的首地址。

fputs函數(shù)的作用是向指定的文件輸出一個(gè)字符串。調(diào)用形式:

fputs(buffer,fp);

作用:將內(nèi)存buffer中的字符串寫到fp指向的文件中,buffer可以是一個(gè)字符串常量,也可以是字符串的首地址。

例10-2

將字符串?"VisualC++"?和?"Visualbasic"?依次存入文件text中,然后將第一個(gè)字符串讀出并顯示出來。/*源程序10-2*/

#include"stdio.h"

main()

{

FILE*fp;

charstring[20];

fp=fopen("text","w+");

fputs("VisualC++\n",fp);

fputs("Visualbasic\n",fp);

rewind(fp);

fgets(string,20,fp);

puts(string);

fclose(fp);

}

這兩個(gè)函數(shù)類似以前介紹過的gets和puts函數(shù),只是fgets和fputs函數(shù)以指定的文件作為讀寫對(duì)象。10.2.4fwrite和fread函數(shù)

getc和putc函數(shù)可以用來讀寫文件中的一個(gè)字符,但是常常要求一次讀入一組數(shù)據(jù)(例如,一個(gè)實(shí)數(shù)或一個(gè)結(jié)構(gòu)體變量的值)。ANSIC標(biāo)準(zhǔn)提出設(shè)置兩個(gè)函數(shù)(fread和fwrite),用來讀寫一個(gè)數(shù)據(jù)塊。

fwrite函數(shù)的功能是把內(nèi)存中的一些數(shù)據(jù)塊寫到指定的文件中。

一般調(diào)用形式:

fwrite(buffer,size,count,fp);其中:

①fp是接受數(shù)據(jù)的文件指針;

②buffer是數(shù)據(jù)塊的內(nèi)存首地址,通常是指針變量名、數(shù)組名等;

③size是一個(gè)數(shù)據(jù)塊的字節(jié)數(shù)(即數(shù)據(jù)塊的大小);

④count是執(zhí)行一次fwrite函數(shù)從內(nèi)存輸出到fp文件的數(shù)據(jù)塊數(shù)目。

例如,下面的語句將把內(nèi)存中結(jié)構(gòu)體數(shù)組stud的數(shù)據(jù)輸出到fp指向的文件中:

for(i=0;i<40;i++)

fwrite(&stud[i],sizeof(structstudent_type),1,fp);以下的語句,一次就把40個(gè)學(xué)生的數(shù)據(jù)輸出到文件中:

fwrite(stud,sizeof(structstudent_type),40,fp);

fread函數(shù)把指定文件中的一個(gè)數(shù)據(jù)塊讀到內(nèi)存中。

一般調(diào)用形式:

fread(buffer,size,count,fp);

其中:

①fp是讀取數(shù)據(jù)的文件指針;

②buffer是接受文件數(shù)據(jù)的內(nèi)存首地址,通常是指針變量名、數(shù)組名等;

③size是一個(gè)數(shù)據(jù)塊的字節(jié)數(shù)(即數(shù)據(jù)塊的大小);

④count是執(zhí)行一次fread()函數(shù)讀取的數(shù)據(jù)塊的數(shù)目。例如,設(shè)string.txt是一個(gè)文本文件,s是長(zhǎng)度為50的char型一維數(shù)組,則執(zhí)行如下語句后,將讀出string.txt文件中的前10個(gè)字符,并依次存儲(chǔ)到數(shù)組s的前10個(gè)元素中:

FILE*fp;

fp=fopen("string.txt","r");

fread(s,2,5,fp);再如,設(shè)有如下定義:

structstudent_type

{

charname[10];

intnum;

intage;

}stud[40];其中,結(jié)構(gòu)體數(shù)組stud的每一個(gè)元素用來存放一個(gè)學(xué)生的有關(guān)數(shù)據(jù)。假設(shè)學(xué)生的數(shù)據(jù)已存放在磁盤文件中,且該文件已打開,并由fp指向,則可以用下面的語句把文件中前40個(gè)學(xué)生的數(shù)據(jù)輸入到結(jié)構(gòu)體數(shù)組stud中:

for(i=0;i<40;i++)

fread(&stud[i],sizeof(structstudent_type),1,fp);

例10-3

從鍵盤輸入4個(gè)學(xué)生的有關(guān)數(shù)據(jù),然后把它們轉(zhuǎn)存到磁盤文件上去。/*源程序10-3*/

#include<stdio.h>

#defineSIZE4

structstudent_type

{

charname[10];

intnum;

intage;

charaddr[15];

}stud[SIZE];

voidsave(

)

{

FILEfp;

inti;

if((fp=fopen("stu-list","wb"))==NULL)

{

printf("cannotopenfile\n");

return;

}

for(i=0;i<SIZE;i++)

if(fwrite(&stud[i],sizeof(structstudent_type),1,fp)!=1)

printf("filewriteerror\n");

fclose(fp);}

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(

);

}在main函數(shù)中,從終端鍵盤輸入4個(gè)學(xué)生的數(shù)據(jù),然后調(diào)用save函數(shù),將這些數(shù)據(jù)輸出到以“stu_list”命名的磁盤文件中。fwrite函數(shù)的作用是將一個(gè)長(zhǎng)度為29字節(jié)的數(shù)據(jù)塊送到stu_list文件中(一個(gè)student_type類型結(jié)構(gòu)體變量的長(zhǎng)度為它的成員長(zhǎng)度之和,即10+2+2+15=29)。運(yùn)行情況如下:

輸入4個(gè)學(xué)生的姓名、學(xué)號(hào)、年齡和地址:

Zhang

1001

19 room-101

Fun 1002 20 room-102

Tan 1003 21 room-103

Ling 1004 21 room-104程序運(yùn)行時(shí),屏幕上并無任何輸出信息,只是將從鍵盤輸入的數(shù)據(jù)送到磁盤文件上。為了驗(yàn)證在磁盤文件“stu_list”中是否已存在此數(shù)據(jù),可以用以下程序從“stu_list”文件中讀入數(shù)據(jù),然后在屏幕上輸出。/*源程序10-4*/

#include<stdio.h>

#defineSIZE4

structstudent-type

{

charname[10];

intnum;

intage;

charaddr[15];

}stud[SIZE];

main()

{

inti;

FILE*fp;

fp=fopen("stu_list","rb");

for(i=0;i<SIZE;i++)

{

fread(&stud[i],sizeof(structstudent_type),1,fp);

printf("%-10s%4d%4d%-5s\n",stud[i].name,&stud[i].

num,&stud[i].

Age,stud[i].addr);

fclose(fp);

}程序運(yùn)行時(shí)不需從鍵盤輸入任何數(shù)據(jù)。屏幕上顯示出以下信息:

Zhang 1001 19 room-101

Fun 1002 20 room-102

Tan 1003 21 room-103

Ling 1004 21 room-104請(qǐng)注意輸入/輸出數(shù)據(jù)的狀況。從鍵盤輸入4個(gè)學(xué)生的數(shù)據(jù)是ASCII碼,也就是文本文件。在送到計(jì)算機(jī)內(nèi)存時(shí),回車和換行符轉(zhuǎn)換成一個(gè)換行符。再從內(nèi)存以“wb”方式(二進(jìn)制寫)輸出到“stu_list”文件,此時(shí)不發(fā)生字符轉(zhuǎn)換,按內(nèi)存中的存儲(chǔ)形式原樣輸出到磁盤文件上。在上面驗(yàn)證程序中,又用fread函數(shù)從“stu_list”文件向內(nèi)存讀入數(shù)據(jù),注意此時(shí)用的是“rb”方式,即二進(jìn)制方式,數(shù)據(jù)按原樣輸入,也不發(fā)生字符轉(zhuǎn)換。也就是這時(shí)候內(nèi)存中的數(shù)據(jù)恢復(fù)到“stu-list”輸出以前的情況。最后在驗(yàn)證程序中,用printf函數(shù)輸出到屏幕。printf是格式輸出函數(shù),輸出ASCII碼,在屏幕上顯示字符。換行符又轉(zhuǎn)換為回車加換行符。如果企圖從“stu_list”文件中以“r”方式讀入數(shù)據(jù)就會(huì)出錯(cuò)。

fread和fwrite函數(shù)一般用于二進(jìn)制文件的輸入/輸出。因?yàn)樗鼈兪前磾?shù)據(jù)塊的長(zhǎng)度來處理輸入/輸出的,所以在字符發(fā)生轉(zhuǎn)換的情況下很可能出現(xiàn)與原設(shè)想不同的情況。

例如,如果用

fread(&stud[i],sizeof(structstudent-type),1,stdin);

企圖從終端鍵盤輸入數(shù)據(jù),這在語法上并不存在錯(cuò)誤,編譯能通過。如果用以下形式輸入數(shù)據(jù):

Zhang1001

10

room-101

…由于fread函數(shù)要求一次輸入29個(gè)字節(jié)(而不問這些字節(jié)的內(nèi)容),因此輸入數(shù)據(jù)中的空格也作為輸入數(shù)據(jù)而不作為數(shù)據(jù)間的分隔符,連空格也存儲(chǔ)到stud[i]中,顯然這是不對(duì)的。

這個(gè)題目要求的是從鍵盤輸入數(shù)據(jù),如果已有的數(shù)據(jù)已以二進(jìn)制形式存儲(chǔ)在一個(gè)磁盤文件“stu-dat”中,要求從其中讀入數(shù)據(jù)并輸出到“stu-list”文件中,則可以編寫一個(gè)load函數(shù),從磁盤文件中讀二進(jìn)制數(shù)據(jù)。/*源程序10-5*/

voidload(

)

{

FILE*fp;

inti;

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)){fclose(fp);return;}

printf("filereaderror\n");

}

fclose(fp);

}將load函數(shù)加到本題原來的程序文件中,并將main函數(shù)改為:

main(

)

{

load(

);

save(

);

}

10.3文件定位

10.3.1rewind函數(shù)

rewind函數(shù)的作用是使位置指針重新返回文件的開頭。此函數(shù)沒有返回值。

例10-4

有一個(gè)磁盤文件,第一次將它的內(nèi)容顯示在屏幕上,第二次把它復(fù)制到另一文件中。/*源程序10-6*/

#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);

}在第一次將文件的內(nèi)容顯示在屏幕以后,文件file1.c的位置指針已指到文件末尾,feof的值為非零(真)。執(zhí)行rewind函數(shù),使文件的位置指針重新定位于文件開頭,并使feof函數(shù)的值恢復(fù)為0(假)。

10.3.2fseek函數(shù)

功能:改變文件位置指針。

調(diào)用形式:

fseek(fp,offset,position);說明:

(1)?fp為文件型指針;

(2)文件位置指針的定位由參數(shù)offset和position共同確定。position規(guī)定指針定位時(shí)的基準(zhǔn)位置;offset規(guī)定文件位置指針離開基準(zhǔn)位置的偏移量,它的單位是字節(jié)。p

溫馨提示

  • 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)論