




版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
1、第13章 文 件,13.1文件概述 13.2文件類型指針 13.3文件的打開(kāi)與關(guān)閉 13.4文件的讀寫(xiě) 13.5文件的定位 13.6出錯(cuò)的檢測(cè) 13.7文件輸入輸出小結(jié) 習(xí)題,13.1C文件概述 文件(file)是程序設(shè)計(jì)中一個(gè)重要的概念。所謂“文件”一般指存儲(chǔ)在外部介質(zhì)上數(shù)據(jù)的集合。一批數(shù)據(jù)是以文件的形式存放在外部介質(zhì)(如磁盤(pán))上的。操作系統(tǒng)是以文件為單位對(duì)數(shù)據(jù)進(jìn)行管理的,也就是說(shuō),如果想找存在外部介質(zhì)上的數(shù)據(jù),必須先按文件名找到所指定的文件,然后再?gòu)脑撐募凶x取數(shù)據(jù)。要向外部介質(zhì)上存儲(chǔ)數(shù)據(jù)也必須先建立一個(gè)文件(以文件名標(biāo)識(shí)),才能向它輸出數(shù)據(jù)。 以前各章中所用到的輸入和輸出,都是以終端為對(duì)
2、象的,即從終端鍵盤(pán)輸入數(shù)據(jù),運(yùn)行結(jié)果輸出到終端上。從操作系統(tǒng)的角度看,每一個(gè)與主機(jī)相聯(lián)的輸入輸出設(shè)備都看作是一個(gè)文件。例如,終端鍵盤(pán)是輸入文件,,顯示屏和打印機(jī)是輸出文件。 在程序運(yùn)行時(shí),常常需要將一些數(shù)據(jù)(運(yùn)行的最終結(jié)果或中間數(shù)據(jù))輸出到磁盤(pán)上存放起來(lái),以后需要時(shí)再?gòu)拇疟P(pán)中輸入到計(jì)算機(jī)內(nèi)存。這就要用到磁盤(pán)文件。 C語(yǔ)言把文件看作是一個(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ǔ)形式原樣輸出到
3、磁盤(pán)上存放。如果有一個(gè)整數(shù)10000,在內(nèi)存中占2個(gè)字節(jié),如果按ASCII碼形式輸出,則占5個(gè)字節(jié),,而按二進(jìn)制形式輸出,在磁盤(pán)上只占2個(gè)字節(jié),見(jiàn)圖13.1。用ASCII碼形式輸出與字符一一對(duì)應(yīng),一個(gè)字節(jié)代表一個(gè)字符,一個(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)制文件保存。,圖13.1 由前所述,一個(gè)C文件是一個(gè)字節(jié)流或二進(jìn)制流。
4、它把數(shù)據(jù)看作是一連串的字符(字節(jié)),而不考慮記錄的界限。換句話說(shuō),C語(yǔ)言中文件并不是由記錄(record)組成的(這是和PASCAL或其他高級(jí)語(yǔ)言不同的)。在C語(yǔ)言中對(duì)文件的存取是以字符(字節(jié))為單位的。輸入輸出的數(shù)據(jù)流的開(kāi)始和結(jié)束僅受程序控制而不受物理符號(hào)(如回車(chē)換行符)控制。,也就是說(shuō),在輸出時(shí)不會(huì)自動(dòng)增加回車(chē)換行符以作為記錄結(jié)束的標(biāo)志,輸入時(shí)不以回車(chē)換行符作為記錄的間隔(事實(shí)上C文件并不由記錄構(gòu)成)。我們把這種文件稱為流式文件。C語(yǔ)言允許對(duì)文件存取一個(gè)字符,這就增加了處理的靈活性。 在過(guò)去使用的C版本(如UNIX系統(tǒng)下使用的C)有兩種對(duì)文件的處理方法:一種叫“緩沖文件系統(tǒng)”,一種叫“非緩
5、沖文件系統(tǒng)”。所謂緩沖文件系統(tǒng)是指系統(tǒng)自動(dòng)地在內(nèi)存區(qū)為每一個(gè)正在使用的文件名開(kāi)辟一個(gè)緩沖區(qū)。從內(nèi)存向磁盤(pán)輸出數(shù)據(jù)必須先送到內(nèi)存中的緩沖區(qū),裝滿緩沖區(qū)后才一起送到磁盤(pán)去。如果從磁盤(pán)向內(nèi)存讀入數(shù)據(jù),則一次從磁盤(pán)文件將一批數(shù)據(jù)輸入到內(nèi)存緩沖區(qū)(充滿緩沖區(qū)),然后再,圖13.2,從緩沖區(qū)逐個(gè)地將數(shù)據(jù)送到程序數(shù)據(jù)區(qū)(給程序變量)。見(jiàn)圖13.2。緩沖區(qū)的大小由各個(gè)具體的C版本確定,一般為512字節(jié)。,所謂“非緩沖文件系統(tǒng)”是指系統(tǒng)不自動(dòng)開(kāi)辟確定大小的緩沖區(qū),而由程序?yàn)槊總€(gè)文件設(shè)定緩沖區(qū)。 在UNIX系統(tǒng)下,用緩沖文件系統(tǒng)來(lái)處理文本文件,用非緩沖文件系統(tǒng)處理二進(jìn)制文件。用緩沖文件系統(tǒng)進(jìn)行的輸入輸出又稱為高級(jí)
6、(或高層)磁盤(pán)輸入輸出(高層I/O),用非緩沖文件系統(tǒng)進(jìn)行的輸入輸出又稱為低級(jí)(低層)輸入輸出系統(tǒng)。ANSI C標(biāo)準(zhǔn)決定不采用非緩沖文件系統(tǒng),而只采用緩沖文件系統(tǒng)。即既用緩沖文件系統(tǒng)處理文本文件,也用它來(lái)處理二進(jìn)制文件。也就是將緩沖文件系統(tǒng)擴(kuò)充為可以處理二進(jìn)制文件。 在C語(yǔ)言中,沒(méi)有輸入輸出語(yǔ)句,對(duì)文件的讀寫(xiě)都是用庫(kù)函數(shù)來(lái)實(shí)現(xiàn)的。ANSI規(guī)定了標(biāo)準(zhǔn)輸入輸,出函數(shù),用它們對(duì)文件進(jìn)行讀寫(xiě)。 本章只介紹ANSI C規(guī)定的文件系統(tǒng)以及對(duì)它的讀寫(xiě)。 13.2文件類型指針 緩沖文件系統(tǒng)中,關(guān)鍵的概念是“文件指針”。每個(gè)被使用的文件都在內(nèi)存中開(kāi)辟一個(gè)區(qū),用來(lái)存放文件的有關(guān)信息(如文件的名字、文件狀態(tài)及文件當(dāng)
7、前位置等)。這些信息是保存在一個(gè)結(jié)構(gòu)體變量中的。該結(jié)構(gòu)體類型是由系統(tǒng)定義的,取名為FILE。Turbo C在stdio.h文件中有以下的文件類型聲明:,typedefstruct shortlevel; /*緩沖區(qū)“滿”或“空”的程度*/ unsignedflags; /*文件狀態(tài)標(biāo)志*/ charfd; /*文件描述符*/ unsignedcharhold; /*如無(wú)緩沖區(qū)不讀取字符*/ shortbsize; /*緩沖區(qū)的大小*/ unsignedchar*baffer;/*數(shù)據(jù)緩沖區(qū)的位置*/ unsignedar*curp;/*指針,當(dāng)前的指向*/ unsignedistemp;/*臨
8、時(shí)文件,指示器*/ shorttoken;/*用于有效性檢查*/ FILE;,有了結(jié)構(gòu)體FILE類型之后,可以用它來(lái)定義若干個(gè)FILE類型的變量,以便存放若干個(gè)文件的信息。例如,可以定義以下FILE類型的數(shù)組。FILEf5;定義了一個(gè)結(jié)構(gòu)體數(shù)組f,它有5個(gè)元素,可以用來(lái)存放5個(gè)文件的信息。 可以定義文件型指針變量。如: FILEfp; fp是一個(gè)指向FILE類型結(jié)構(gòu)體的指針變量??梢允筬p指向某一個(gè)文件的結(jié)構(gòu)體變量,從而通過(guò)該結(jié)構(gòu)體變量中的文件信息能夠訪問(wèn)該文件。也就是說(shuō),通過(guò)文件指針變量能夠找到與它相關(guān)的文件。如果有n個(gè)文件,一般應(yīng)設(shè)n個(gè)指針變量(指向FILE類型結(jié)構(gòu)體的指針變量),使它們分
9、別指向,n個(gè)文件(確切地說(shuō)指向存放該文件信息的結(jié)構(gòu)體變量),以實(shí)現(xiàn)對(duì)文件的訪問(wèn)。 13.3文件的打開(kāi)與關(guān)閉 和其他高級(jí)語(yǔ)言一樣,對(duì)文件讀寫(xiě)之前應(yīng)該“打開(kāi)”該文件,在使用結(jié)束之后應(yīng)關(guān)閉該文件。 13.3.1文件的打開(kāi)(fopen函數(shù)) ANSI C規(guī)定了標(biāo)準(zhǔn)輸入輸出函數(shù)庫(kù),用fopen()函數(shù)來(lái)實(shí)現(xiàn)打開(kāi)文件。,fopen函數(shù)的調(diào)用方式通常為 FILEfp; fp=fopen(文件名,使用文件方式); 例如: fp=fopen(a1,r); 它表示要打開(kāi)名字為a1的文件,使用文件方式為“讀入” (r代表read,即讀入),fopen函數(shù)帶回指向a1文件的指針并賦給fp,這樣fp就和文件a1相聯(lián)系了
10、,或者說(shuō),fp指向a1文件??梢钥闯?,在打開(kāi)一個(gè)文件時(shí),通知給編譯系統(tǒng)以下3個(gè)信息:需要打開(kāi)的文件名,也就是準(zhǔn)備訪問(wèn)的文件的名字。,使用文件的方式(“讀”還是“寫(xiě)”等)。 讓哪一個(gè)指針變量指向被打開(kāi)的文件。 說(shuō)明: (1) 用“r”方式打開(kāi)的文件只能用于向計(jì)算機(jī)輸入而不能用作向該文件輸出數(shù)據(jù),而且該文件應(yīng)該已經(jīng)存在,不能用“r”方式打開(kāi)一個(gè)并不存在的文件(即輸入文件),否則出錯(cuò)。 (2) 用“w”方式打開(kāi)的文件只能用于向該文件寫(xiě)數(shù)據(jù)(即輸出文件),而不能用來(lái)向計(jì)算機(jī)輸入。如果原來(lái)不存在該文件,則在打開(kāi)時(shí)新建立一個(gè)以指定的名字命名的文件。如果原來(lái)已存在一個(gè)以該文件名命名的文件,則在打開(kāi)時(shí)將該文件
11、刪去,然后重新建立一個(gè)新文件。,(3) 如果希望向文件末尾添加新的數(shù)據(jù)(不希望刪除原有數(shù)據(jù)),則應(yīng)該用“a”方式打開(kāi)。但此時(shí)該文件必須已存在,否則將得到出錯(cuò)信息。打開(kāi)時(shí),位置指針移到文件末尾。 (4) 用“r+”、“w+”、“a+”方式打開(kāi)的文件既可以用來(lái)輸入數(shù)據(jù),也可以用來(lái)輸出數(shù)據(jù)。用“r+”方式時(shí)該文件應(yīng)該已經(jīng)存在,以便能向計(jì)算機(jī)輸入數(shù)據(jù)。用“w+”方式則新建立一個(gè)文件,先向此文件寫(xiě)數(shù)據(jù),然后可以讀此文件中的數(shù)據(jù)。用“a+”方式打開(kāi)的文件,原來(lái)的文件不被刪去,位置指針移到文件末尾,可以添加,也可以讀。 (5) 如果不能實(shí)現(xiàn)“打開(kāi)”的任務(wù),fopen函數(shù)將會(huì)帶回一個(gè)出錯(cuò)信息。出錯(cuò)的原因可能是
12、用“r”方式,打開(kāi)一個(gè)并不存在的文件;磁盤(pán)出故障;磁盤(pán)已滿無(wú)法建立新文件等。此時(shí)fopen函數(shù)將帶回一個(gè)空指針值NULL(NULL在stdioh文件中已被定義為0)。 常用下面的方法打開(kāi)一個(gè)文件: if(fp=fopen(file1,r)=NULL) printf(cannot open this filen); exit(0); 即先檢查打開(kāi)的操作有否出錯(cuò),如果有錯(cuò)就在終端上輸出“cannot open this file”。exit函數(shù)的作用是關(guān)閉所有文件,終止正在調(diào)用的過(guò)程。待用戶檢查出錯(cuò)誤,修改后再運(yùn)行。,(6) 用以上方式可以打開(kāi)文本文件或二進(jìn)制文件,這是ANSI C的規(guī)定,用同一種
13、緩沖文件系統(tǒng)來(lái)處理文本文件和二進(jìn)制文件。但目前使用的有些C編譯系統(tǒng)可能不完全提供所有這些功能(例如有的只能用“r”、“w”、“a”方式),有的C版本不用“r+”、“w+”、“a+”,而用“rw”、“wr”、“ar”等,請(qǐng)讀者注意所用系統(tǒng)的規(guī)定。 (7) 在向計(jì)算機(jī)輸入文本文件時(shí),將回車(chē)換行符轉(zhuǎn)換為一個(gè)換行符,在輸出時(shí)把換行符轉(zhuǎn)換成為回車(chē)和換行兩個(gè)字符。在用二進(jìn)制文件時(shí),不進(jìn)行這種轉(zhuǎn)換,在內(nèi)存中的數(shù)據(jù)形式與輸出到外部文件中的數(shù)據(jù)形式完全一致,一一對(duì)應(yīng)。,(8) 在程序開(kāi)始運(yùn)行時(shí),系統(tǒng)自動(dòng)打開(kāi)3個(gè)標(biāo)準(zhǔn)文件:標(biāo)準(zhǔn)輸入、標(biāo)準(zhǔn)輸出、標(biāo)準(zhǔn)出錯(cuò)輸出。通常這3個(gè)文件都與終端相聯(lián)系。因此以前我們所用到的從終端輸
14、入或輸出都不需要打開(kāi)終端文件。系統(tǒng)自動(dòng)定義了3個(gè)文件指針stdin、stdout和stderr,分別指向終端輸入、終端輸出和標(biāo)準(zhǔn)出錯(cuò)輸?也從終端輸出)。如果程序中指定要從stdin所指的文件輸入數(shù)據(jù),就是指從終端鍵盤(pán)輸入數(shù)據(jù)。 13.3.2文件的關(guān)閉(fclose函數(shù)) 在使用完一個(gè)文件后應(yīng)該關(guān)閉它,以防止它再被誤用?!瓣P(guān)閉”就是使文件指針變量不指向該文件,,也就是文件指針變量與文件“脫鉤”,此后不能再通過(guò)該指針對(duì)原來(lái)與其相聯(lián)系的文件進(jìn)行讀寫(xiě)操作。除非再次打開(kāi),使該指針變量重新指向該文件。 用fclose函數(shù)關(guān)閉文件。fclose函數(shù)調(diào)用的一般形式為 fclose(文件指針); 例如: fcl
15、ose(fp); 前面我們?cè)汛蜷_(kāi)文件(用fopen函數(shù))時(shí)所帶回的指針賦給了fp,今通過(guò)fp把該文件關(guān)閉。即fp不再指向該文件。,應(yīng)該養(yǎng)成在程序終止之前關(guān)閉所有文件的習(xí)慣,如果不關(guān)閉文件將會(huì)丟失數(shù)據(jù)。因?yàn)?,如前所述,在向文件?xiě)數(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è)問(wèn)題,它先把緩沖區(qū)中的數(shù)據(jù)輸出到磁盤(pán)文件,然后才釋放文件指針變量。 fclose函數(shù)也帶回一個(gè)值,當(dāng)順利地執(zhí)行了關(guān)閉操作,則返回值為0;否則返回EOF(-1)??梢杂胒error函數(shù)來(lái)測(cè)試(見(jiàn)13.61節(jié))
16、。,13.4文 件 的 讀 寫(xiě) 文件打開(kāi)之后,就可以對(duì)它進(jìn)行讀寫(xiě)了。常用的讀寫(xiě)函數(shù)如下所述。 13.4.1fputc函數(shù)和fgetc函數(shù)(putc函數(shù)和getc函數(shù)) 1.fputc函數(shù) 把一個(gè)字符寫(xiě)到磁盤(pán)文件上去。其一般調(diào)用形式為 fputc(ch,fp); 其中ch是要輸出的字符,它可以是一個(gè)字符常量,也可以是一個(gè)字符變量。fp是文件指針變量。fputc(ch,fp)函數(shù)的作用是將字符(ch的值)輸出到fp所指向的文件中去。fputc函數(shù)也帶回一個(gè)值:,如果輸出成功則返回值就是輸出的字符;如果輸出失敗,則返回一個(gè)EOF(-1)。EOF是在stdioh文件中定義的符號(hào)常量,值為-1。在第4章
17、介紹過(guò)putchar函數(shù),其實(shí)putchar是從fputc函數(shù)派生出來(lái)的。putchar(c)是在stdio.h文件中用預(yù)處理命令#define定義的宏:#defineputchar(c)fputc(c,stdout)前面已敘述,stdout是系統(tǒng)定義的文件指針變量,它與終端輸出相連。fputc(c瑂tdout)的作用是將c的值輸出到終端。用宏putchar(c)比寫(xiě)fputc(c,stdout)簡(jiǎn)單一些。從用戶的角度,可以把putchar(c)看作函數(shù)而不必嚴(yán)格地稱它為宏。,2. fgetc函數(shù) 從指定的文件讀入一個(gè)字符,該文件必須是以讀或讀寫(xiě)方式打開(kāi)的。fgetc函數(shù)的調(diào)用形式為 ch=f
18、getc(fp); fp為文件型指針變量,ch為字符變量。fgetc函數(shù)帶回一個(gè)字符,賦給ch。如果在執(zhí)行fgetc函數(shù)讀字符時(shí)遇到文件結(jié)束符,函數(shù)返回一個(gè)文件結(jié)束標(biāo)志EOF(-1)。如果想從一個(gè)磁盤(pán)文件順序讀入字符并在屏幕上顯示出來(lái),可以:,ch=fgetc(fp); while(ch!=EOF) putchar(ch); ch=fgetc(fp); 注意:EOF不是可輸出字符,因此不能在屏幕上顯示。由于字符的ASCII碼不可能出現(xiàn)-1,因此EOF定義為-1是合適的。當(dāng)讀入的字符值等于-1(即EOF)時(shí),表示讀入的已不是正常的字符而是文件結(jié)束符。但以上只適用于讀文本文件的情況?,F(xiàn)在ANSI
19、C已允許用緩沖文件系統(tǒng)處理二進(jìn)制文件,而讀入某一個(gè)字節(jié)中的二進(jìn)制數(shù)據(jù)的值有可能是-1,而這又,恰好是EOF的值。這就出現(xiàn)了需要讀入有用數(shù)據(jù)而卻被處理為“文件結(jié)束”的情況。為了解決這個(gè)問(wèn)題,ANSI C提供一個(gè)feof函數(shù)來(lái)判斷文件是否真的結(jié)束。feof(fp)用來(lái)測(cè)試fp所指向的文件當(dāng)前狀態(tài)是否“文件結(jié)束”。如果是文件結(jié)束,函數(shù)feof(fp)的值為1(真),否則為0(假)。 如果想順序讀入一個(gè)二進(jìn)制文件中的數(shù)據(jù),可以用 while(!feof(fp) c=fgetc(fp); ,當(dāng)未遇文件結(jié)束,feof(fp)的值為0,!feof(fp)為1,讀入一個(gè)字節(jié)的數(shù)據(jù)賦給整型變量c,并接著對(duì)其進(jìn)行
20、所需的處理。直到遇文件結(jié)束,feof(fp)值為1,!feof(fp)值為0,不再執(zhí)行while循環(huán)。 這種方法也適用于文本文件。 3. fputc和fgetc函數(shù)使用舉例 在掌握了以上幾種函數(shù)以后,可以編制一些簡(jiǎn)單的使用文件的程序。 例13.1從鍵盤(pán)輸入一些字符,逐個(gè)把它們送到磁盤(pán)上去,直到輸入一個(gè)“#”為止。,#include main() FILEfp; char ch,filename10; scanf(%s,filename); if(fp=fopen(filename,w)=NULL) printf(cannot open filen); exit(0); ch=getchar(
21、);/*此語(yǔ)句用來(lái)接收在執(zhí)行scanf語(yǔ)句時(shí)最后輸入的回車(chē)符*/ ch=getchar();/*接收輸入的第一個(gè)字符*/,while(ch!=#) fputc(ch,fp);putchar(ch); ch=getchar(); fclose(fp); 運(yùn)行情況如下: file1c (輸入磁盤(pán)文件名) computer and c#(輸入一個(gè)字符串) computer and c (輸出一個(gè)字符串),文件名由鍵盤(pán)輸入,賦給字符數(shù)組filename,fopen函數(shù)中的第一個(gè)參數(shù)“文件名”可以直接寫(xiě)成字符串常量形式(如“file1c”),也可以用字符數(shù)組名,在字符數(shù)組中存放文件名(如本例所用的方法)
22、。本例運(yùn)行時(shí),從鍵盤(pán)輸入磁盤(pán)文件名“file1c”,然后輸入要寫(xiě)入該磁盤(pán)文件的字符“computer and c”,“#”是表示輸入結(jié)束,程序?qū)ⅰ癱omputer and c”寫(xiě)到以“file1c”命名的磁盤(pán)文件中,同時(shí)在屏幕上顯示這些字符,以便核對(duì)。 可以用DOS命令將file1c文件中的內(nèi)容打印出來(lái):Ctype file1c computer and c,證明了在file1c文件中已存入了“computer and c”的信息。 例13.2將一個(gè)磁盤(pán)文件中的信息復(fù)制到另一個(gè)磁盤(pán)文件中。 #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(輸入原有磁盤(pán)文件名) Enter the outfile name: file2c(輸入新復(fù)制的磁盤(pán)文件名),程序運(yùn)行結(jié)果是將file1c文件中的內(nèi)容復(fù)制到file2c中去??梢杂孟旅鍰OS命令驗(yàn)證 ctype file1c computer and c(file1c中的信息) ctype file2c computer and c(file2c中的信息) 以上程序是按文本文件方式處理的。也可以用此程序來(lái)復(fù)制一個(gè)二進(jìn)制文件,只需將兩個(gè)fopen函數(shù)中的“r”和“w”分別改為“rb”和“wb”即可。 也可以在
25、輸入命令行時(shí)把兩個(gè)文件名一起輸入。這時(shí)要用到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í)行文件名后,再輸入兩個(gè)參數(shù)file1c和file2c,分別輸入到argv1和argv2中,argv0的內(nèi)容為a,argc的值等于3(因?yàn)榇嗣钚泄灿?個(gè)參數(shù))。如果輸入的參數(shù)少于3個(gè),則程序會(huì)輸出:“你忘了輸入一個(gè)文件名”。程序執(zhí)行結(jié)果是將file1c中的信息復(fù)制到file2c中??梢杂靡韵旅铗?yàn)證:,Ctype file1c
27、computer and c (這是file1c文件中的信息) Ctype file2c computer and c (這是file2c文件中的信息。可見(jiàn)file1c已復(fù)制到file2c中了)。 最后說(shuō)明一點(diǎn),為了書(shū)寫(xiě)方便,系統(tǒng)把fputc和fgetc定義為宏名putc和getc: #define putc(ch,fp) fputc(ch,fp) #define getc(fp) fgetc(fp),這是在stdioh中定義的。因此,用putc和fputc及用getc和fgetc是一樣的。一般可以把它們作為相同的函數(shù)來(lái)對(duì)待。 13.4.2fread函數(shù)和fwrite函數(shù) 用getc和putc
28、函數(shù)可以用來(lái)讀寫(xiě)文件中的一個(gè)字符。但是常常要求一次讀入一組數(shù)據(jù)(例如,一個(gè)實(shí)數(shù)或一個(gè)結(jié)構(gòu)體變量的值),ANSI C標(biāo)準(zhǔn)提出設(shè)置兩個(gè)函數(shù)(fread和fwrite),用來(lái)讀寫(xiě)一個(gè)數(shù)據(jù)塊。它們的一般調(diào)用形式為 fread(buffer,sie,count,fp); fwrite(buffer,sie,count,fp);,其中: buffer:是一個(gè)指針。對(duì)fread來(lái)說(shuō),它是讀入數(shù)據(jù)的存放地址。對(duì)fwrite來(lái)說(shuō),是要輸出數(shù)據(jù)的地址(以上指的是起始地址)。 size:要讀寫(xiě)的字節(jié)數(shù)。 count:要進(jìn)行讀寫(xiě)多少個(gè)sie字節(jié)的數(shù)據(jù)項(xiàng)。 fp:文件型指針。 如果文件以二進(jìn)制形式打開(kāi),用fread和f
29、write函數(shù)就可以讀寫(xiě)任何類型的信息,如: fread(f,4,2,fp); 其中f是一個(gè)實(shí)型數(shù)組名。一個(gè)實(shí)型變量占4個(gè)字節(jié)。,這個(gè)函數(shù)從fp所指向的文件讀入2次(每次4個(gè)字節(jié))數(shù)據(jù),存儲(chǔ)到數(shù)組f中。 如果有一個(gè)如下的結(jié)構(gòu)體類型: structstudent-type char name10; int num; int age; charaddr30; stud40; 結(jié)構(gòu)體數(shù)組stud有40個(gè)元素,每一個(gè)元素用來(lái)存放一個(gè)學(xué)生的數(shù)據(jù)(包括姓名、學(xué)號(hào)、年齡、地址)。,假設(shè)學(xué)生的數(shù)據(jù)已存放在磁盤(pán)文件中,可以用下面的for語(yǔ)句和fread函數(shù)讀入40個(gè)學(xué)生的數(shù)據(jù): for(i=0;i40;i+)
30、fread( 如果fread或fwrite調(diào)用成功,則函數(shù)返回值為count的值,即輸入或輸出數(shù)據(jù)項(xiàng)的完整個(gè)數(shù)。,下面寫(xiě)出一個(gè)完整的程序。 例13.3從鍵盤(pán)輸入4個(gè)學(xué)生的有關(guān)數(shù)據(jù),然后把它們轉(zhuǎn)存到磁盤(pá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ù)中,從終端鍵盤(pán)輸入4個(gè)學(xué)生的數(shù)據(jù),然后調(diào)用save函數(shù),將這些數(shù)據(jù)輸出到以“stu_list”命名的磁盤(pán)文件中。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)、年齡和地址: Zhang100119room-101,Fun 1002 20 room-102 Tan 1003 21 room-103 Ling 1004 21 room-104 程序
32、運(yùn)行時(shí),屏幕上并無(wú)輸出任何信息,只是將從鍵盤(pán)輸入的數(shù)據(jù)送到磁盤(pán)文件上。為了驗(yàn)證在磁盤(pán)文件“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í)不需從鍵盤(pán)輸入任何數(shù)據(jù)。屏幕上顯示出以下信息: Zhan
33、g100119room-101 Fun 1002 20 room-102,Tan 1003 21 room-103 Ling 1004 21 room-104 請(qǐng)注意輸入輸出數(shù)據(jù)的狀況。從鍵盤(pán)輸入4個(gè)學(xué)生的數(shù)據(jù)是ASCII碼,也就是文本文件。在送到計(jì)算機(jī)內(nèi)存時(shí),回車(chē)和換行符轉(zhuǎn)換成一個(gè)換行符。再?gòu)膬?nèi)存以“wb”方式 (二進(jìn)制寫(xiě))輸出到“stu_list”文件,此時(shí)不發(fā)生字符轉(zhuǎn)換,按內(nèi)存中存儲(chǔ)形式原樣輸出到磁盤(pán)文件上。在上面驗(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ù)
34、到第一個(gè)程序向,“stu-list”輸出以前的情況。最后在驗(yàn)證程序中,用printf函數(shù)輸出到屏幕,printf是格式輸出函數(shù),輸出ASCII碼,在屏幕上顯示字符。換行符又轉(zhuǎn)換為回車(chē)加換行符。 如果企圖從“stu_list”文件中以“r”方式讀入數(shù)據(jù)就會(huì)出錯(cuò)。 fread和fwrite函數(shù)一般用于二進(jìn)制文件的輸入輸出。因?yàn)樗鼈兪前磾?shù)據(jù)塊的長(zhǎng)度來(lái)處理輸入輸出的,在字符發(fā)生轉(zhuǎn)換的情況下很可能出現(xiàn)與原設(shè)想的情況不同。 例如,如果寫(xiě)fread(,企圖從終端鍵盤(pán)輸入數(shù)據(jù),這在語(yǔ)法上并不存在錯(cuò)誤,編譯能通過(guò)。如果用以下形式輸入數(shù)據(jù): Zhang 100110room-101 由于fread函數(shù)要求一次輸入
35、29個(gè)字節(jié)(而不問(wèn)這些字節(jié)的內(nèi)容),因此輸入數(shù)據(jù)中的空格也作為輸入數(shù)據(jù)而不作為數(shù)據(jù)間的分隔符了。連空格也存儲(chǔ)到studi中了,顯然是不對(duì)的。 這個(gè)題目要求的是從鍵盤(pán)輸入數(shù)據(jù),如果已有的數(shù)據(jù)已以二進(jìn)制形式存儲(chǔ)在一個(gè)磁盤(pán)文件“stu-dat”中,要求從其中讀入數(shù)據(jù)并輸出到“stu-list”文件中,可以編寫(xiě)一個(gè)load函數(shù),從磁盤(pán)文件中讀,二進(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ù)加到本題原來(lái)的程序文件中,并將main函數(shù)改為main() load(); save(); ,13.4.3fprintf函數(shù)和fscanf函數(shù) fprintf函數(shù)、fscanf函數(shù)與printf函數(shù)、scanf函數(shù)作用相仿,都是格式化讀寫(xiě)函數(shù)。只有一點(diǎn)不同:fprintf和fscanf函數(shù)的讀寫(xiě)對(duì)象不是終端而是磁盤(pán)文件。它們的一般調(diào)用方式為fprintf(文件指針,格式字符串,輸出表列);fscanf (文件指針,格式字符串,輸入表列);例如: fprintf(fp,%d,%62f,i,t)
37、; 它的作用是將整型變量i和實(shí)型變量t的值按%d和%62f的格式輸出到fp指向的文件上。如果i=3,t=45,則輸出到磁盤(pán)文件上的是以下的字符串:,3,450 同樣,用以下fscanf函數(shù)可以從磁盤(pán)文件上讀入ASCII字符:fscanf(fp,%d,%f, 磁盤(pán)文件上如果有以下字符: 3,45 則將磁盤(pán)文件中的數(shù)據(jù)3送給變量i,45送給變量t。 用fprintf和fscanf函數(shù)對(duì)磁盤(pán)文件讀寫(xiě),使用方便,容易理解,但由于在輸入時(shí)要將ASCII碼轉(zhuǎn)換為二進(jìn)制形式,在輸出時(shí)又要將二進(jìn)制形式轉(zhuǎn)換成字符,花費(fèi)時(shí)間比較多。因此,在內(nèi)存與磁盤(pán)頻繁交換數(shù)據(jù)的情況下,最好不用fprintf和,fscanf函數(shù)
38、,而用fread和fwrite函數(shù)。 13.4.4其他讀寫(xiě)函數(shù) 1. putw和getw函數(shù) 大多數(shù)C編譯系統(tǒng)都提供另外兩個(gè)函數(shù):putw和getw,用來(lái)對(duì)磁盤(pán)文件讀寫(xiě)一個(gè)字(整數(shù))。例如: putw(10,fp); 它的作用是將整數(shù)10輸出到fp指向的文件。而i=getw(fp);的作用是從磁盤(pán)文件讀一個(gè)整數(shù)到內(nèi)存,賦給整型變量i。 如果所用的C編譯的庫(kù)函數(shù)中不包括putw和getw函數(shù),可以自己定義該兩函數(shù)。putw函數(shù)如下:,putw(int i,F(xiàn)ILE *fp) chars; s=(char*)”語(yǔ)句,形參i得到實(shí)參傳來(lái)的值10,在putw函數(shù)中將i的地址賦予指針變量s,而s是指向字
39、符變量的指針變量,因此s指向i的第1個(gè)字節(jié),s+1指向i的第2個(gè)字節(jié)。由于*(s+0)就是s0,*(s+1)就是s1,因此,s0、s1分別對(duì)應(yīng)i的第1字節(jié)和第2個(gè)字節(jié)。由于,圖13.3,*(s+0)就是s0,*(s+1)就是s1,因此,s0、s1分別對(duì)應(yīng)i的第1字節(jié)和第2字節(jié)。順序輸出s0、s1就相當(dāng)于輸出了i的兩個(gè)字節(jié)中的內(nèi)容。見(jiàn)圖13.3。,getw函數(shù)如下: getw(FILE *fp) chars; int i; s=(char *) putw和getw并不是ANSI C標(biāo)準(zhǔn)定義的函數(shù)。但許多C編譯都提供這兩個(gè)函數(shù),但有的C編譯可能不,以putw和getw命名此兩函數(shù),而用其他函數(shù)名,
40、請(qǐng)用時(shí)注意。 2. 讀寫(xiě)其他類型數(shù)據(jù) 如果用ANSI C提供的fread和fwrite函數(shù),讀寫(xiě)任何類型數(shù)據(jù)都是十分方便的。如果所用的系統(tǒng)不提供這兩個(gè)函數(shù),用戶只好自己定義所需函數(shù)。例如,可以定義一個(gè)向磁盤(pán)文件寫(xiě)一個(gè)實(shí)數(shù)(用二進(jìn)制方式)的函數(shù)putfloat: putfloat(float num,F(xiàn)ILE *fp) chars;,int count; s=(char *) n為要求得到的字符,但只從fp指向的文件輸入n-1個(gè)字符,然后在最后加一個(gè)0字符,因此得到,的字符串共有n個(gè)字符。把它們放到字符數(shù)組str中。如果在讀完n-1個(gè)字符之前遇到換行符或EOF,讀入即結(jié)束。fgets函數(shù)返回值為
41、str的首地址。 fputs函數(shù)的作用是向指定的文件輸出一個(gè)字符串。如:fputs(China,fp);把字符串“China”輸出到fp指向的文件。fputs函數(shù)中第一個(gè)參數(shù)可以是字符串常量、字符數(shù)組名或字符型指針。字符串末尾的0 不輸出。若輸出成功,函數(shù)值為0;失敗時(shí),為EOF。 這兩個(gè)函數(shù)類似以前介紹過(guò)的gets和puts函數(shù),只是fgets和fputs函數(shù)以指定的文件作為讀寫(xiě)對(duì)象。,13.5文 件 的 定 位 文件中有一個(gè)位置指針,指向當(dāng)前讀寫(xiě)的位置。如果順序讀寫(xiě)一個(gè)文件,每次讀寫(xiě)一個(gè)字符,則讀寫(xiě)完一個(gè)字符后,該位置指針自動(dòng)移動(dòng)指向下一個(gè)字符位置。如果想改變這樣的規(guī)律,強(qiáng)制使位置指針指向
42、其他指定的位置,可以用有關(guān)函數(shù)。 13.5.1rewind函數(shù) rewind函數(shù)的作用是使位置指針重新返回文件的開(kāi)頭。此函數(shù)沒(méi)有返回值。 例13.4有一個(gè)磁盤(pán)文件,第一次將它的內(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ù),使文件的位置指針重,新定位于文件開(kāi)頭,并使feof函數(shù)的值恢復(fù)為0(假)。 13.5.2fseek函數(shù)和隨機(jī)讀寫(xiě) 對(duì)流式文件可以進(jìn)行順序讀寫(xiě),也可以進(jìn)行隨機(jī)讀寫(xiě)。關(guān)鍵在于控制文件的位置指針,如果位置指針是按字節(jié)位置順序移動(dòng)的,就是順序讀寫(xiě)。如果能將位置指針按需要移動(dòng)到任意位置,就可以實(shí)現(xiàn)隨機(jī)讀寫(xiě)。所謂隨機(jī)讀寫(xiě),是指讀寫(xiě)完上一個(gè)字符(字節(jié))后,并不一定要讀寫(xiě)其后續(xù)的址?字節(jié)),而可以讀寫(xiě)文件中任意所需的字符(字節(jié))。 用fseek函數(shù)可以實(shí)現(xiàn)改變文件的位置指針。,fseek函數(shù)的調(diào)用
44、形式為fseek(文件類型指針,位移量,起始點(diǎn)) “起始點(diǎn)”用0、1或2代替,0代表“文件開(kāi)始”,1為“當(dāng)前位置”,2為“文件末尾”。ANSI C標(biāo)準(zhǔn)指定的名字如表13.2所示。 “位移量”指以“起始點(diǎn)”為基點(diǎn),向前移動(dòng)的字節(jié)數(shù)。ANSI C和大多數(shù)C版本要求位移量是long型數(shù)據(jù)。這樣當(dāng)文件的長(zhǎng)度大于64時(shí)不致出問(wèn)題。ANSI C標(biāo)準(zhǔn)規(guī)定在數(shù)字的末尾加一個(gè)字母L,就表示是long型。 下面是fseek函數(shù)調(diào)用的幾個(gè)例子: fseek(fp,100L,0);將位置指針移到離文件頭100個(gè)字節(jié)處,fseek(fp,50L,1); 將位置指針移到離當(dāng)前位置50個(gè)字節(jié)處 fseek(fp,-10L,2); 將位置指針從文件末尾處向后退10個(gè)字節(jié) 利用fseek函數(shù)就可以實(shí)現(xiàn)隨機(jī)讀寫(xiě)了。 例13.5在磁盤(pán)文件上存有10個(gè)學(xué)生的數(shù)據(jù)。要求將第1、3、5、7、9個(gè)學(xué)生數(shù)據(jù)輸入計(jì)算機(jī),并在屏幕上顯示出來(lái)。 程序如下: #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. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝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ù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
- 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ì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 模糊神經(jīng)網(wǎng)絡(luò)在船舶狀態(tài)智能監(jiān)測(cè)中的應(yīng)用研究
- 景區(qū)行政執(zhí)法管理辦法
- 核酸混合試劑管理辦法
- 電力大數(shù)據(jù)助力金融智能化風(fēng)控
- 供熱設(shè)備檢修管理辦法
- 公共衛(wèi)生中心管理辦法
- 物流行業(yè)的集聚效應(yīng)、技術(shù)創(chuàng)新與高質(zhì)量發(fā)展路徑
- 培訓(xùn)機(jī)構(gòu)審批管理辦法
- 普貨運(yùn)輸安全生產(chǎn)管理制度
- 教師培訓(xùn)方案:有效處理幼兒告狀行為的策略探討
- 2025至2030中國(guó)改裝車(chē)行業(yè)深度發(fā)展研究與企業(yè)投資戰(zhàn)略規(guī)劃報(bào)告
- 中醫(yī)執(zhí)業(yè)醫(yī)師歷年真題及解答
- MT/T 1222-2024液壓支架再制造工程設(shè)計(jì)指南
- 2025年7月浙江省普通高中學(xué)業(yè)水平考試歷史仿真模擬卷01(含答案)
- 2024-2025學(xué)年人教版PEP六年級(jí)下學(xué)期期末試卷(含答案含聽(tīng)力原文無(wú)音頻)
- 2025-2030年中國(guó)聚脲涂料行業(yè)市場(chǎng)現(xiàn)狀供需分析及投資評(píng)估規(guī)劃分析研究報(bào)告
- 一級(jí)建造師考試安全管理試題及答案
- 鍍鋅板知識(shí)課件
- 2025-2030偏光成像相機(jī)行業(yè)市場(chǎng)現(xiàn)狀供需分析及重點(diǎn)企業(yè)投資評(píng)估規(guī)劃分析研究報(bào)告
- 豬場(chǎng)退股協(xié)議書(shū)范本
- 2025海南保亭農(nóng)水投資有限公司招聘22人筆試參考題庫(kù)附帶答案詳解
評(píng)論
0/150
提交評(píng)論