




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)
文檔簡介
第八章
文件第八章
文件C文件概述文件類型指針文件的打開和關(guān)閉文件的讀寫文件的定位出錯的檢測文件的輸入輸出小結(jié)C文件概述(一)C文件概述(一)C文件概述C文件概述文件(file)是程序設(shè)計中一個重要的概念。所謂“文件”一般指存儲在外部介質(zhì)上數(shù)據(jù)的集合。一批數(shù)據(jù)是以文件的形式存放在外部介質(zhì)(如磁盤)上的。操作系統(tǒng)是以文件為單位對數(shù)據(jù)進行管理的,也就是說,如果想找存在外部介質(zhì)上的數(shù)據(jù),必須先按文件名找到所指定的文件,然后再從該文件中讀取數(shù)據(jù)。要向外部介質(zhì)上存儲數(shù)據(jù)也必須先建立一個文件(以文件名標識),才能向它輸出數(shù)據(jù)。以前各章中所用到的輸入和輸出,都是以終端為對象的,即從終端鍵盤輸入數(shù)據(jù),運行結(jié)果輸出到終端上。從操作系統(tǒng)的角度看,每一個與主機相聯(lián)的輸入輸出設(shè)備都看作是一個文件。例如,終端鍵盤是輸入文件,顯示屏和打印機是輸出文件。C文件概述文件(file)是程序設(shè)計中一個重要的概念。C文件概述在程序運行時,常常需要將一些數(shù)據(jù)(運行的最終結(jié)果或中間數(shù)據(jù))輸出到磁盤上存放起來,以后需要時再從磁盤中輸入到計算機內(nèi)存。這就要用到磁盤文件。C語言把文件看作是一個字符(字節(jié))的序列,即由一個一個字符(字節(jié))的數(shù)據(jù)順序組成。根據(jù)數(shù)據(jù)的組織形式,可分為ASCII文件和二進制文件。ASCII文件又稱文本(text)文件,它的每一個字節(jié)放一個ASCII代碼,代表一個字符。二進制文件是把內(nèi)存中的數(shù)據(jù)按其在內(nèi)存中的存儲形式原樣輸出到磁盤上存放。如果有一個整數(shù)10000,在內(nèi)存中占4個字節(jié),如果按ASCII碼形式輸出,則占5個字節(jié),而按二進制形式輸出,在磁盤上只占4個字節(jié)。用ASCII碼形式輸出與字符一一對應(yīng),一個字節(jié)代表一個字符,一個字節(jié)代表一個字符,因而便于對字符進行逐個處理,也便于輸出字符。但一般占存儲空間較多,而且要花費轉(zhuǎn)換時間(二進制形式與ASCII碼間的轉(zhuǎn)換)。用二進制形式輸出數(shù)值,可以節(jié)省外存空間和轉(zhuǎn)換時間,但一個字節(jié)并不對應(yīng)一個字符,不能直接輸出字符形式。一般中間結(jié)果數(shù)據(jù)需要暫時保存在外存上以后又需要輸入到內(nèi)存的,常用二進制文件保存。C文件概述在程序運行時,常常需要將一些數(shù)據(jù)(運行的最終結(jié)果或C文件概述由前所述,一個C文件是一個字節(jié)流或二進制流。它把數(shù)據(jù)看作是一連串的字符(字節(jié)),而不考慮記錄的界限。換句話說,C語言中文件并不是由記錄(record)組成的。在C語言中對文件的存取是以字符(字節(jié))為單位的。輸入輸出的數(shù)據(jù)流的開始和結(jié)束僅受程序控制而不受物理符號(如回車換行符)控制。也就是說,在輸出時不會自動增加回車換行符以作為記錄結(jié)束的標志,輸入時不以回車換行符作為記錄的間隔(事實上C文件并不由記錄構(gòu)成)。我們把這種文件稱為流式文件。C語言允許對文件存取一個字符,這就增加了處理的靈活性。在C語言中,沒有輸入輸出語句,對文件的讀寫都是用庫函數(shù)來實現(xiàn)的。ANSI規(guī)定了標準輸入輸出函數(shù),用它們對文件進行讀寫。C文件概述由前所述,一個C文件是一個字節(jié)流或二進制流。它把數(shù)C文件概述有兩種對文件的處理方法:一種叫“緩沖文件系統(tǒng)”;一種叫“非緩沖文件系統(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ū)),然后再從緩沖區(qū)逐個地將數(shù)據(jù)送到程序數(shù)據(jù)區(qū)(給程序變量)。如下圖所示。緩沖區(qū)的大小由各個具體的C版本確定,一般為512字節(jié)。C文件概述有兩種對文件的處理方法:C語言第9章-文件教學(xué)課件C文件概述所謂“非緩沖文件系統(tǒng)”是指系統(tǒng)不自動開辟確定大小的緩沖區(qū),而由程序為每個文件設(shè)定緩沖區(qū)。在UNIX系統(tǒng)下,用緩沖文件系統(tǒng)來處理文本文件,用非緩沖文件系統(tǒng)處理二進制文件。用緩沖文件系統(tǒng)進行的輸入輸出又稱為高級(或高層)磁盤輸入輸出(高層I/O)。用非緩沖文件系統(tǒng)進行的輸入輸出又稱為低級(低層)輸入輸出系統(tǒng)。ANSIC標準決定不采用非緩沖文件系統(tǒng),而只采用緩沖文件系統(tǒng)。即既用緩沖文件系統(tǒng)處理文本文件,也用它來處理二進制文件。也就是將緩沖文件系統(tǒng)擴充為可以處理二進制文件。本章只介紹ANSIC規(guī)定的文件系統(tǒng)以及對它的讀寫。C文件概述所謂“非緩沖文件系統(tǒng)”是指系統(tǒng)不自動開辟確定大小的(二)文件類型指針(二)文件類型指針文件類型指針緩沖文件系統(tǒng)中,關(guān)鍵的概念是“文件指針”。每個被使用的文件都在內(nèi)存中開辟一個區(qū),用來存放文件的有關(guān)信息(如文件的名字、文件狀態(tài)及文件當前位置等)。這些信息是保存在一個結(jié)構(gòu)體變量中的。該結(jié)構(gòu)體類型是由系統(tǒng)定義的,取名為FILE。TurboC在stdio.h文件中有以下的文件類型聲明:文件類型指針緩沖文件系統(tǒng)中,關(guān)鍵的概念是“文件指針”。每個被typedefstruct{ shortlevel;/*緩沖區(qū)“滿”或“空”的程度*/ unsignedflags;/*文件狀態(tài)標志*/ charfd;/*文件描述符*/ unsignedcharhold;/*如無緩沖區(qū)不讀取字符*/ shortbsize;/*緩沖區(qū)的大小*/ unsignedchar*baffer;/*數(shù)據(jù)緩沖區(qū)的位置*/ unsignedar*curp;/*指針,當前的指向*/ unsignedistemp;/*臨時文件,指示器*/ shorttoken;/*用于有效性檢查*/}FILE;typedefstruct文件類型指針可以定義文件型指針變量。如: FILEfp;如果有n個文件,一般應(yīng)設(shè)n個指針變量(指向FILE類型結(jié)構(gòu)體的指針變量),使它們分別指向n個文件(確切地說指向存放該文件信息的結(jié)構(gòu)體變量),以實現(xiàn)對文件的訪問。文件類型指針可以定義文件型指針變量。如:(三)文件的打開與關(guān)閉(三)文件的打開與關(guān)閉文件打開fopen函數(shù)對文件讀寫之前應(yīng)該“打開”該文件,在使用結(jié)束之后應(yīng)關(guān)閉該文件。ANSIC規(guī)定了標準輸入輸出函數(shù)庫,用fopen()函數(shù)來實現(xiàn)打開文件。fopen函數(shù)的調(diào)用方式通常為 FILE*fp; fp=fopen(文件名,使用文件方式);例如: fp=fopen("a1","r");可以看出,在打開一個文件時,通知給編譯系統(tǒng)以下3個信息:
①需要打開的文件名,也就是準備訪問的文件的名字。②使用文件的方式(“讀”還是“寫”等)。③讓哪一個指針變量指向被打開的文件。文件打開fopen函數(shù)對文件讀寫之前應(yīng)該“打開”該文件,在使文件打開fopen函數(shù)文件使用方式參見書上P333表13-1。說明:1)用“r”方式:只讀方式,打開的文件只能用于向計算機輸入而不能用作向該文件輸出數(shù)據(jù),而且該文件應(yīng)該已經(jīng)存在,不能用“r”方式打開一個并不存在的文件(即輸入文件),否則出錯。2)用“w”方式:只寫方式,打開的文件只能用于向該文件寫數(shù)據(jù)(即輸出文件),而不能用來向計算機輸入。如果原來不存在該文件,則在打開時新建立一個以指定的名字命名的文件。如果原來已存在一個以該文件名命名的文件,則在打開時將該文件刪去,然后重新建立一個新文件。文件打開fopen函數(shù)文件使用方式參見書上P333表13-1文件打開fopen函數(shù)3)如果希望向文件末尾添加新的數(shù)據(jù)(不希望刪除原有數(shù)據(jù)),則應(yīng)該用“a”方式打開。但此時該文件必須已存在,否則將得到出錯信息。打開時,位置指針移到文件末尾。4)用“r+”、“w+”、“a+”方式打開的文件既可以用來輸入數(shù)據(jù),也可以用來輸出數(shù)據(jù)。用“r+”方式時該文件應(yīng)該已經(jīng)存在,以便能向計算機輸入數(shù)據(jù)。用“w+”方式則新建立一個文件,先向此文件寫數(shù)據(jù),然后可以讀此文件中的數(shù)據(jù)。用“a+”方式打開的文件,原來的文件不被刪去,位置指針移到文件末尾,可以添加,也可以讀。文件打開fopen函數(shù)3)如果希望向文件末尾添加新的數(shù)據(jù)(不文件打開fopen函數(shù)5)如果不能實現(xiàn)“打開”的任務(wù),fopen函數(shù)將會帶回一個出錯信息。出錯的原因可能是用“r”方式打開一個并不存在的文件;磁盤出故障;磁盤已滿無法建立新文件等。此時fopen函數(shù)將帶回一個空指針值NULL(NULL在stdio.h文件中已被定義為0)。常用下面的方法打開一個文件: if((fp=fopen("file1","r"))==NULL) { printf("cannotopenthisfile\n"); …… }即先檢查打開的操作有否出錯,如果有錯就在終端上輸出“cannotopenthisfile”。文件打開fopen函數(shù)5)如果不能實現(xiàn)“打開”的任務(wù),fop文件打開fopen函數(shù)6)用以上方式可以打開文本文件或二進制文件,這是ANSIC的規(guī)定,用同一種緩沖文件系統(tǒng)來處理文本文件和二進制文件。但目前使用的有些C編譯系統(tǒng)可能不完全提供所有這些功能(例如有的只能用“r”、“w”、“a”方式),有的C版本不用“r+”、“w+”、“a+”,而用“rw”、“wr”、“ar”等,請讀者注意所用系統(tǒng)的規(guī)定。(7)在向計算機輸入文本文件時,將回車換行符轉(zhuǎn)換為一個換行符,在輸出時把換行符轉(zhuǎn)換成為回車和換行兩個字符。在用二進制文件時,不進行這種轉(zhuǎn)換,在內(nèi)存中的數(shù)據(jù)形式與輸出到外部文件中的數(shù)據(jù)形式完全一致,一一對應(yīng)。文件打開fopen函數(shù)6)用以上方式可以打開文本文件或二進制文件打開fopen函數(shù)8)在程序開始運行時,系統(tǒng)自動打開3個標準文件:標準輸入、標準輸出、標準出錯輸出。通常這3個文件都與終端相聯(lián)系。因此以前我們所用到的從終端輸入或輸出都不需要打開終端文件。系統(tǒng)自動定義了3個文件指針stdin、stdout和stderr,分別指向終端輸入、終端輸出和標準出錯輸?也從終端輸出)。如果程序中指定要從stdin所指的文件輸入數(shù)據(jù),就是指從終端鍵盤輸入數(shù)據(jù)。文件打開fopen函數(shù)8)在程序開始運行時,系統(tǒng)自動打開3個文件關(guān)閉fclose函數(shù)在使用完一個文件后應(yīng)該關(guān)閉它,以防止它再被誤用?!瓣P(guān)閉”就是使文件指針變量不指向該文件,也就是文件指針變量與文件“脫鉤”,此后不能再通過該指針對原來與其相聯(lián)系的文件進行讀寫操作。除非再次打開,使該指針變量重新指向該文件。用fclose函數(shù)關(guān)閉文件。fclose函數(shù)調(diào)用的一般形式為 fclose(文件指針);例如: fclose(fp);fclose函數(shù)也帶回一個值,當順利地執(zhí)行了關(guān)閉操作,則返回值為0;否則返回EOF(-1)。文件關(guān)閉fclose函數(shù)在使用完一個文件后應(yīng)該關(guān)閉它,以防止文件關(guān)閉fclose函數(shù)應(yīng)該養(yǎng)成在程序終止之前關(guān)閉所有文件的習(xí)慣,如果不關(guān)閉文件將會丟失數(shù)據(jù)。因為,如前所述,在向文件寫數(shù)據(jù)時,是先將數(shù)據(jù)輸?shù)骄彌_區(qū),待緩沖區(qū)充滿后才正式輸出給文件。如果當數(shù)據(jù)未充滿緩沖區(qū)而程序結(jié)束運行,就會將緩沖區(qū)中的數(shù)據(jù)丟失。用fclose函數(shù)關(guān)閉文件,可以避免這個問題,它先把緩沖區(qū)中的數(shù)據(jù)輸出到磁盤文件,然后才釋放文件指針變量。文件關(guān)閉fclose函數(shù)應(yīng)該養(yǎng)成在程序終止之前關(guān)閉所有文件的(四)文件的讀寫(四)文件的讀寫fputc寫文件函數(shù)把一個字符寫到磁盤文件上去。其一般調(diào)用形式為: fputc(ch,fp);其中:ch是要輸出的字符,它可以是一個字符常量,也可以是一個字符變量。fp是文件指針變量。fputc(ch,fp)函數(shù)的作用是將字符(ch的值)輸出到fp所指向的文件中去。fputc函數(shù)也帶回一個值:如果輸出成功則返回值就是輸出的字符;如果輸出失敗,則返回一個EOF(-1)。EOF是在stdio.h文件中定義的符號常量,值為-1。fputc寫文件函數(shù)把一個字符寫到磁盤文件上去。其一般調(diào)用形fputc寫文件函數(shù)在前面介紹過putchar函數(shù),其實putchar是從fputc函數(shù)派生出來的。putchar(c)是在stdio.h文件中用預(yù)處理命令#define定義的宏:#defineputchar(c)fputc(c,stdout)前面已敘述,stdout是系統(tǒng)定義的文件指針變量,它與終端輸出相連。fputc(c,stdout)的作用是將c的值輸出到終端。用宏putchar(c)比寫fputc(c,stdout)簡單一些。從用戶的角度,可以把putchar(c)看作函數(shù)而不必嚴格地稱它為宏。fputc寫文件函數(shù)在前面介紹過putchar函數(shù),其實pufgetc讀文件函數(shù)從指定的文件讀入一個字符,該文件必須是以讀或讀寫方式打開的。fgetc函數(shù)的調(diào)用形式為 ch=fgetc(fp);fp為文件型指針變量,ch為字符變量。fgetc函數(shù)帶回一個字符,賦給ch。如果在執(zhí)行fgetc函數(shù)讀字符時遇到文件結(jié)束符,函數(shù)返回一個文件結(jié)束標志EOF(-1)。如果想從一個磁盤文件順序讀入字符并在屏幕上顯示出來,可以: ch=fgetc(fp); while(ch!=EOF) { putchar(ch); ch=fgetc(fp);}fgetc讀文件函數(shù)從指定的文件讀入一個字符,該文件必須是以feof()判斷文件是否結(jié)束函數(shù)注意:EOF不是可輸出字符,因此不能在屏幕上顯示。由于字符的ASCII碼不可能出現(xiàn)-1,因此EOF定義為-1是合適的。當讀入的字符值等于-1(即EOF)時,表示讀入的已不是正常的字符而是文件結(jié)束符。但以上只適用于讀文本文件的情況。現(xiàn)在ANSIC已允許用緩沖文件系統(tǒng)處理二進制文件,而讀入某一個字節(jié)中的二進制數(shù)據(jù)的值有可能是-1,而這又恰好是EOF的值。這就出現(xiàn)了需要讀入有用數(shù)據(jù)而卻被處理為“文件結(jié)束”的情況。為了解決這個問題,ANSIC提供一個feof函數(shù)來判斷文件是否真的結(jié)束。 feof(fp)用來測試fp所指向的文件當前狀態(tài)是否“文件結(jié)束”。如果是文件結(jié)束,函數(shù)feof(fp)的值為1(真),否則為0(假)。feof()判斷文件是否結(jié)束函數(shù)注意:EOF不是可輸出字符,feof()判斷文件是否結(jié)束函數(shù)如: while(!feof(fp)) { c=fgetc(fp); …}feof()判斷文件是否結(jié)束函數(shù)如:fputc和fgetc舉例例12.1從鍵盤輸入一些字符,逐個把它們送到磁盤上去,直到輸入一個“#”為止。源碼參見12-1.c例12.2將一個磁盤文件中的信息復(fù)制到另一個磁盤文件中。源碼參見12-2\a.c使用命令行方式輸入兩個文件名;源碼參見12-2\b.cfputc和fgetc舉例例12.1從鍵盤輸入一些字符,逐fread和fwrite函數(shù)ANSIC標準提出設(shè)置兩個函數(shù)(fread和fwrite),用來讀寫一個數(shù)據(jù)塊。它們的一般調(diào)用形式為 fread(buffer,size,count,fp); fwrite(buffer,size,count,fp);其中:buffer:是一個指針。對fread來說,它是讀入數(shù)據(jù)的存放地址。對fwrite來說,是要輸出數(shù)據(jù)的地址(以上指的是起始地址)。size:要讀寫的字節(jié)數(shù)。count:要進行讀寫多少個size字節(jié)的數(shù)據(jù)項。fp:文件型指針。如果fread或fwrite調(diào)用成功,則函數(shù)返回值為count的值,即輸入或輸出數(shù)據(jù)項的完整個數(shù)。fread和fwrite函數(shù)ANSIC標準提出設(shè)置兩個函數(shù)fread和fwrite函數(shù)如果文件以二進制形式打開,用fread和fwrite函數(shù)就可以讀寫任何類型的信息,如: fread(f,4,2,fp);其中f是一個實型數(shù)組名。一個實型變量占4個字節(jié)。這個函數(shù)從fp所指向的文件讀入2次(每次4個字節(jié))數(shù)據(jù),存儲到數(shù)組f中。fread和fwrite函數(shù)如果文件以二進制形式打開,用frfread和fwrite函數(shù)如果有一個如下的結(jié)構(gòu)體類型: structstudent-type { charname[10]; intnum; intage; charaddr[30]; }stud[40];假設(shè)學(xué)生的數(shù)據(jù)已存放在磁盤文件中,可以用下面的for語句和fread函數(shù)讀入40個學(xué)生的數(shù)據(jù): for(i=0;i<40;i++) { fread(&stud[i],sizeof(structstudent-type),1,fp); }同樣,以下for語句和fwrite函數(shù)可以將內(nèi)存中的學(xué)生數(shù)據(jù)輸出到磁盤文件中去: for(i=0;i<40,i++) { fwrite(&stud[i],sizeof(structstudent-type),1,fp); }fread和fwrite函數(shù)如果有一個如下的結(jié)構(gòu)體類型:fread和fwrite函數(shù)舉例例12.3從鍵盤輸入4個學(xué)生的有關(guān)數(shù)據(jù),然后把它們轉(zhuǎn)存到磁盤文件上去。源碼參見12-3fread和fwrite函數(shù)舉例例12.3從鍵盤輸入4個學(xué)其它讀寫函數(shù)自學(xué)。其它讀寫函數(shù)自學(xué)。(五)文件的定位(五)文件的定位文件中有一個位置指針,指向當前讀寫的位置。如果順序讀寫一個文件,每次讀寫一個字符,則讀寫完一個字符后,該位置指針自動移動指向下一個字符位置。如果想改變這樣的規(guī)律,強制使位置指針指向其他指定的位置,可以用有關(guān)函數(shù)。文件中有一個位置指針,指向當前讀寫的位置。如果順序讀寫一個文rewind函數(shù)rewind函數(shù)的作用是使位置指針重新返回文件的開頭。此函數(shù)沒有返回值。例12.4有一個磁盤文件,第一次將它的內(nèi)容顯示在屏幕上,第二次把它復(fù)制到另一文件上。源碼參見12-4.crewind函數(shù)rewind函數(shù)的作用是使位置指針重新返回文fseek函數(shù)和隨機讀寫對流式文件可以進行順序讀寫,也可以進行隨機讀寫。關(guān)鍵在于控制文件的位置指針,如果位置指針是按字節(jié)位置順序移動的,就是順序讀寫。如果能將位置指針按需要移動到任意位置,就可以實現(xiàn)隨機讀寫。所謂隨機讀寫,是指讀寫完上一個字符(字節(jié))后,并不一定要讀寫其后續(xù)的字符(字節(jié)),而可以讀寫文件中任意所需的字符(字節(jié))。用fseek函數(shù)可以實現(xiàn)改變文件的位置指針。fseek函數(shù)和隨機讀寫對流式文件可以進行順序讀寫,也可以進fseek函數(shù)和隨機讀寫fseek函數(shù)的調(diào)用形式為: fseek(文件類型指針,位移量,起始點)其中:“起始點”用0、1或2代替,0代表“文件開始”,1為“當前位置”,2為“文件末尾”。ANSIC標準指定的名字如表13.2所示(見書上P345)。“位移量”指以“起始點”為基點,向前移動的字節(jié)數(shù)。ANSIC和大多數(shù)C版本要求位移量是long型數(shù)據(jù)。這樣當文件的長度大于64K時不致出問題。ANSIC標準規(guī)定在數(shù)字的末尾加一個字母L,就表示是long型。下面是fseek函數(shù)調(diào)用的幾個例子:fseek(fp,100L,0);將位置指針移到離文件頭100個字節(jié)處fseek(fp,50L,1);將位置指針移到離當前位置50個字節(jié)處fseek(fp,-10L,2);將位置指針從文件末尾處向后退10個字節(jié)fseek函數(shù)和隨機讀寫fseek函數(shù)的調(diào)用形式為:fseek示例例12.5在磁盤文件上存有10個學(xué)生的數(shù)據(jù)。要求將第1、3、5、7、9個學(xué)生數(shù)據(jù)輸入計算機,并在屏幕上顯示出來。源代碼參見12-5.cfseek示例例12.5在磁盤文件上存有10個學(xué)生的數(shù)據(jù)。ftell函數(shù)ftell函數(shù)的作用是得到流式文件中的當前位置,用相對于文件開頭的位移量來表示。由于文件中的位置指針經(jīng)常移動,人們往往不容易知道其當前位置。用ftell函數(shù)可以得到當前位置。如果ftell函數(shù)返回值為-1L,表示出錯。例如: i=ftell(fp); if(i==-1L) { printf("error\n"); }ftell函數(shù)ftell函數(shù)的作用是得到流式文件中的當前位置(六)出錯的檢測(六)出錯的檢測ferror函數(shù)在調(diào)用各種輸入輸出函數(shù)(如putc、getc、fread、fwrite等)時,如果出現(xiàn)錯誤,除了函數(shù)返回值有所反映外,還可以用ferror函數(shù)檢查。它的一般調(diào)用形式為: ferror(fp);如果ferror返回值為0(假),表示未出錯。如果返回一個非零值,表示出錯。應(yīng)該注意,對同一個文件每一次調(diào)用輸入輸出函數(shù),均產(chǎn)生一個新的ferror函數(shù)值,因此,應(yīng)當在調(diào)用一個輸入輸出函數(shù)后立即檢查ferror函數(shù)的值,否則信息會丟失。在執(zhí)行fopen函數(shù)時,ferror函數(shù)的初始值自動置為0。ferror函數(shù)在調(diào)用各種輸入輸出函數(shù)(如putc、getcclearerr函數(shù)它的作用是使文件錯誤標志和文件結(jié)束標志置為0。假設(shè)在調(diào)用一個輸入輸出函數(shù)時出現(xiàn)錯誤,ferror函數(shù)值為一個非零值。在調(diào)用clearerr(fp)后,ferror(fp)的值變成0。只要出現(xiàn)錯誤標志,就一直保留,直到對同一文件調(diào)用clearerr函數(shù)或rewind函數(shù),或任何其他一個輸入輸出函數(shù)。clearerr函數(shù)它的作用是使文件錯誤標志和文件結(jié)束標志置(七)文件輸入輸出小結(jié)(七)文件輸入輸出小結(jié)文件使用可以參考表12-3(書P307)和表12-1(書P293);在實際需要時,可以查閱這兩個表。當然,這兩個表列出的內(nèi)容只是常用的函數(shù)和標志。文件使用可以參考表12-3(書P307)和表12-1(書P2第八章
文件第八章
文件C文件概述文件類型指針文件的打開和關(guān)閉文件的讀寫文件的定位出錯的檢測文件的輸入輸出小結(jié)C文件概述(一)C文件概述(一)C文件概述C文件概述文件(file)是程序設(shè)計中一個重要的概念。所謂“文件”一般指存儲在外部介質(zhì)上數(shù)據(jù)的集合。一批數(shù)據(jù)是以文件的形式存放在外部介質(zhì)(如磁盤)上的。操作系統(tǒng)是以文件為單位對數(shù)據(jù)進行管理的,也就是說,如果想找存在外部介質(zhì)上的數(shù)據(jù),必須先按文件名找到所指定的文件,然后再從該文件中讀取數(shù)據(jù)。要向外部介質(zhì)上存儲數(shù)據(jù)也必須先建立一個文件(以文件名標識),才能向它輸出數(shù)據(jù)。以前各章中所用到的輸入和輸出,都是以終端為對象的,即從終端鍵盤輸入數(shù)據(jù),運行結(jié)果輸出到終端上。從操作系統(tǒng)的角度看,每一個與主機相聯(lián)的輸入輸出設(shè)備都看作是一個文件。例如,終端鍵盤是輸入文件,顯示屏和打印機是輸出文件。C文件概述文件(file)是程序設(shè)計中一個重要的概念。C文件概述在程序運行時,常常需要將一些數(shù)據(jù)(運行的最終結(jié)果或中間數(shù)據(jù))輸出到磁盤上存放起來,以后需要時再從磁盤中輸入到計算機內(nèi)存。這就要用到磁盤文件。C語言把文件看作是一個字符(字節(jié))的序列,即由一個一個字符(字節(jié))的數(shù)據(jù)順序組成。根據(jù)數(shù)據(jù)的組織形式,可分為ASCII文件和二進制文件。ASCII文件又稱文本(text)文件,它的每一個字節(jié)放一個ASCII代碼,代表一個字符。二進制文件是把內(nèi)存中的數(shù)據(jù)按其在內(nèi)存中的存儲形式原樣輸出到磁盤上存放。如果有一個整數(shù)10000,在內(nèi)存中占4個字節(jié),如果按ASCII碼形式輸出,則占5個字節(jié),而按二進制形式輸出,在磁盤上只占4個字節(jié)。用ASCII碼形式輸出與字符一一對應(yīng),一個字節(jié)代表一個字符,一個字節(jié)代表一個字符,因而便于對字符進行逐個處理,也便于輸出字符。但一般占存儲空間較多,而且要花費轉(zhuǎn)換時間(二進制形式與ASCII碼間的轉(zhuǎn)換)。用二進制形式輸出數(shù)值,可以節(jié)省外存空間和轉(zhuǎn)換時間,但一個字節(jié)并不對應(yīng)一個字符,不能直接輸出字符形式。一般中間結(jié)果數(shù)據(jù)需要暫時保存在外存上以后又需要輸入到內(nèi)存的,常用二進制文件保存。C文件概述在程序運行時,常常需要將一些數(shù)據(jù)(運行的最終結(jié)果或C文件概述由前所述,一個C文件是一個字節(jié)流或二進制流。它把數(shù)據(jù)看作是一連串的字符(字節(jié)),而不考慮記錄的界限。換句話說,C語言中文件并不是由記錄(record)組成的。在C語言中對文件的存取是以字符(字節(jié))為單位的。輸入輸出的數(shù)據(jù)流的開始和結(jié)束僅受程序控制而不受物理符號(如回車換行符)控制。也就是說,在輸出時不會自動增加回車換行符以作為記錄結(jié)束的標志,輸入時不以回車換行符作為記錄的間隔(事實上C文件并不由記錄構(gòu)成)。我們把這種文件稱為流式文件。C語言允許對文件存取一個字符,這就增加了處理的靈活性。在C語言中,沒有輸入輸出語句,對文件的讀寫都是用庫函數(shù)來實現(xiàn)的。ANSI規(guī)定了標準輸入輸出函數(shù),用它們對文件進行讀寫。C文件概述由前所述,一個C文件是一個字節(jié)流或二進制流。它把數(shù)C文件概述有兩種對文件的處理方法:一種叫“緩沖文件系統(tǒng)”;一種叫“非緩沖文件系統(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ū)),然后再從緩沖區(qū)逐個地將數(shù)據(jù)送到程序數(shù)據(jù)區(qū)(給程序變量)。如下圖所示。緩沖區(qū)的大小由各個具體的C版本確定,一般為512字節(jié)。C文件概述有兩種對文件的處理方法:C語言第9章-文件教學(xué)課件C文件概述所謂“非緩沖文件系統(tǒng)”是指系統(tǒng)不自動開辟確定大小的緩沖區(qū),而由程序為每個文件設(shè)定緩沖區(qū)。在UNIX系統(tǒng)下,用緩沖文件系統(tǒng)來處理文本文件,用非緩沖文件系統(tǒng)處理二進制文件。用緩沖文件系統(tǒng)進行的輸入輸出又稱為高級(或高層)磁盤輸入輸出(高層I/O)。用非緩沖文件系統(tǒng)進行的輸入輸出又稱為低級(低層)輸入輸出系統(tǒng)。ANSIC標準決定不采用非緩沖文件系統(tǒng),而只采用緩沖文件系統(tǒng)。即既用緩沖文件系統(tǒng)處理文本文件,也用它來處理二進制文件。也就是將緩沖文件系統(tǒng)擴充為可以處理二進制文件。本章只介紹ANSIC規(guī)定的文件系統(tǒng)以及對它的讀寫。C文件概述所謂“非緩沖文件系統(tǒng)”是指系統(tǒng)不自動開辟確定大小的(二)文件類型指針(二)文件類型指針文件類型指針緩沖文件系統(tǒng)中,關(guān)鍵的概念是“文件指針”。每個被使用的文件都在內(nèi)存中開辟一個區(qū),用來存放文件的有關(guān)信息(如文件的名字、文件狀態(tài)及文件當前位置等)。這些信息是保存在一個結(jié)構(gòu)體變量中的。該結(jié)構(gòu)體類型是由系統(tǒng)定義的,取名為FILE。TurboC在stdio.h文件中有以下的文件類型聲明:文件類型指針緩沖文件系統(tǒng)中,關(guān)鍵的概念是“文件指針”。每個被typedefstruct{ shortlevel;/*緩沖區(qū)“滿”或“空”的程度*/ unsignedflags;/*文件狀態(tài)標志*/ charfd;/*文件描述符*/ unsignedcharhold;/*如無緩沖區(qū)不讀取字符*/ shortbsize;/*緩沖區(qū)的大小*/ unsignedchar*baffer;/*數(shù)據(jù)緩沖區(qū)的位置*/ unsignedar*curp;/*指針,當前的指向*/ unsignedistemp;/*臨時文件,指示器*/ shorttoken;/*用于有效性檢查*/}FILE;typedefstruct文件類型指針可以定義文件型指針變量。如: FILEfp;如果有n個文件,一般應(yīng)設(shè)n個指針變量(指向FILE類型結(jié)構(gòu)體的指針變量),使它們分別指向n個文件(確切地說指向存放該文件信息的結(jié)構(gòu)體變量),以實現(xiàn)對文件的訪問。文件類型指針可以定義文件型指針變量。如:(三)文件的打開與關(guān)閉(三)文件的打開與關(guān)閉文件打開fopen函數(shù)對文件讀寫之前應(yīng)該“打開”該文件,在使用結(jié)束之后應(yīng)關(guān)閉該文件。ANSIC規(guī)定了標準輸入輸出函數(shù)庫,用fopen()函數(shù)來實現(xiàn)打開文件。fopen函數(shù)的調(diào)用方式通常為 FILE*fp; fp=fopen(文件名,使用文件方式);例如: fp=fopen("a1","r");可以看出,在打開一個文件時,通知給編譯系統(tǒng)以下3個信息:
①需要打開的文件名,也就是準備訪問的文件的名字。②使用文件的方式(“讀”還是“寫”等)。③讓哪一個指針變量指向被打開的文件。文件打開fopen函數(shù)對文件讀寫之前應(yīng)該“打開”該文件,在使文件打開fopen函數(shù)文件使用方式參見書上P333表13-1。說明:1)用“r”方式:只讀方式,打開的文件只能用于向計算機輸入而不能用作向該文件輸出數(shù)據(jù),而且該文件應(yīng)該已經(jīng)存在,不能用“r”方式打開一個并不存在的文件(即輸入文件),否則出錯。2)用“w”方式:只寫方式,打開的文件只能用于向該文件寫數(shù)據(jù)(即輸出文件),而不能用來向計算機輸入。如果原來不存在該文件,則在打開時新建立一個以指定的名字命名的文件。如果原來已存在一個以該文件名命名的文件,則在打開時將該文件刪去,然后重新建立一個新文件。文件打開fopen函數(shù)文件使用方式參見書上P333表13-1文件打開fopen函數(shù)3)如果希望向文件末尾添加新的數(shù)據(jù)(不希望刪除原有數(shù)據(jù)),則應(yīng)該用“a”方式打開。但此時該文件必須已存在,否則將得到出錯信息。打開時,位置指針移到文件末尾。4)用“r+”、“w+”、“a+”方式打開的文件既可以用來輸入數(shù)據(jù),也可以用來輸出數(shù)據(jù)。用“r+”方式時該文件應(yīng)該已經(jīng)存在,以便能向計算機輸入數(shù)據(jù)。用“w+”方式則新建立一個文件,先向此文件寫數(shù)據(jù),然后可以讀此文件中的數(shù)據(jù)。用“a+”方式打開的文件,原來的文件不被刪去,位置指針移到文件末尾,可以添加,也可以讀。文件打開fopen函數(shù)3)如果希望向文件末尾添加新的數(shù)據(jù)(不文件打開fopen函數(shù)5)如果不能實現(xiàn)“打開”的任務(wù),fopen函數(shù)將會帶回一個出錯信息。出錯的原因可能是用“r”方式打開一個并不存在的文件;磁盤出故障;磁盤已滿無法建立新文件等。此時fopen函數(shù)將帶回一個空指針值NULL(NULL在stdio.h文件中已被定義為0)。常用下面的方法打開一個文件: if((fp=fopen("file1","r"))==NULL) { printf("cannotopenthisfile\n"); …… }即先檢查打開的操作有否出錯,如果有錯就在終端上輸出“cannotopenthisfile”。文件打開fopen函數(shù)5)如果不能實現(xiàn)“打開”的任務(wù),fop文件打開fopen函數(shù)6)用以上方式可以打開文本文件或二進制文件,這是ANSIC的規(guī)定,用同一種緩沖文件系統(tǒng)來處理文本文件和二進制文件。但目前使用的有些C編譯系統(tǒng)可能不完全提供所有這些功能(例如有的只能用“r”、“w”、“a”方式),有的C版本不用“r+”、“w+”、“a+”,而用“rw”、“wr”、“ar”等,請讀者注意所用系統(tǒng)的規(guī)定。(7)在向計算機輸入文本文件時,將回車換行符轉(zhuǎn)換為一個換行符,在輸出時把換行符轉(zhuǎn)換成為回車和換行兩個字符。在用二進制文件時,不進行這種轉(zhuǎn)換,在內(nèi)存中的數(shù)據(jù)形式與輸出到外部文件中的數(shù)據(jù)形式完全一致,一一對應(yīng)。文件打開fopen函數(shù)6)用以上方式可以打開文本文件或二進制文件打開fopen函數(shù)8)在程序開始運行時,系統(tǒng)自動打開3個標準文件:標準輸入、標準輸出、標準出錯輸出。通常這3個文件都與終端相聯(lián)系。因此以前我們所用到的從終端輸入或輸出都不需要打開終端文件。系統(tǒng)自動定義了3個文件指針stdin、stdout和stderr,分別指向終端輸入、終端輸出和標準出錯輸?也從終端輸出)。如果程序中指定要從stdin所指的文件輸入數(shù)據(jù),就是指從終端鍵盤輸入數(shù)據(jù)。文件打開fopen函數(shù)8)在程序開始運行時,系統(tǒng)自動打開3個文件關(guān)閉fclose函數(shù)在使用完一個文件后應(yīng)該關(guān)閉它,以防止它再被誤用?!瓣P(guān)閉”就是使文件指針變量不指向該文件,也就是文件指針變量與文件“脫鉤”,此后不能再通過該指針對原來與其相聯(lián)系的文件進行讀寫操作。除非再次打開,使該指針變量重新指向該文件。用fclose函數(shù)關(guān)閉文件。fclose函數(shù)調(diào)用的一般形式為 fclose(文件指針);例如: fclose(fp);fclose函數(shù)也帶回一個值,當順利地執(zhí)行了關(guān)閉操作,則返回值為0;否則返回EOF(-1)。文件關(guān)閉fclose函數(shù)在使用完一個文件后應(yīng)該關(guān)閉它,以防止文件關(guān)閉fclose函數(shù)應(yīng)該養(yǎng)成在程序終止之前關(guān)閉所有文件的習(xí)慣,如果不關(guān)閉文件將會丟失數(shù)據(jù)。因為,如前所述,在向文件寫數(shù)據(jù)時,是先將數(shù)據(jù)輸?shù)骄彌_區(qū),待緩沖區(qū)充滿后才正式輸出給文件。如果當數(shù)據(jù)未充滿緩沖區(qū)而程序結(jié)束運行,就會將緩沖區(qū)中的數(shù)據(jù)丟失。用fclose函數(shù)關(guān)閉文件,可以避免這個問題,它先把緩沖區(qū)中的數(shù)據(jù)輸出到磁盤文件,然后才釋放文件指針變量。文件關(guān)閉fclose函數(shù)應(yīng)該養(yǎng)成在程序終止之前關(guān)閉所有文件的(四)文件的讀寫(四)文件的讀寫fputc寫文件函數(shù)把一個字符寫到磁盤文件上去。其一般調(diào)用形式為: fputc(ch,fp);其中:ch是要輸出的字符,它可以是一個字符常量,也可以是一個字符變量。fp是文件指針變量。fputc(ch,fp)函數(shù)的作用是將字符(ch的值)輸出到fp所指向的文件中去。fputc函數(shù)也帶回一個值:如果輸出成功則返回值就是輸出的字符;如果輸出失敗,則返回一個EOF(-1)。EOF是在stdio.h文件中定義的符號常量,值為-1。fputc寫文件函數(shù)把一個字符寫到磁盤文件上去。其一般調(diào)用形fputc寫文件函數(shù)在前面介紹過putchar函數(shù),其實putchar是從fputc函數(shù)派生出來的。putchar(c)是在stdio.h文件中用預(yù)處理命令#define定義的宏:#defineputchar(c)fputc(c,stdout)前面已敘述,stdout是系統(tǒng)定義的文件指針變量,它與終端輸出相連。fputc(c,stdout)的作用是將c的值輸出到終端。用宏putchar(c)比寫fputc(c,stdout)簡單一些。從用戶的角度,可以把putchar(c)看作函數(shù)而不必嚴格地稱它為宏。fputc寫文件函數(shù)在前面介紹過putchar函數(shù),其實pufgetc讀文件函數(shù)從指定的文件讀入一個字符,該文件必須是以讀或讀寫方式打開的。fgetc函數(shù)的調(diào)用形式為 ch=fgetc(fp);fp為文件型指針變量,ch為字符變量。fgetc函數(shù)帶回一個字符,賦給ch。如果在執(zhí)行fgetc函數(shù)讀字符時遇到文件結(jié)束符,函數(shù)返回一個文件結(jié)束標志EOF(-1)。如果想從一個磁盤文件順序讀入字符并在屏幕上顯示出來,可以: ch=fgetc(fp); while(ch!=EOF) { putchar(ch); ch=fgetc(fp);}fgetc讀文件函數(shù)從指定的文件讀入一個字符,該文件必須是以feof()判斷文件是否結(jié)束函數(shù)注意:EOF不是可輸出字符,因此不能在屏幕上顯示。由于字符的ASCII碼不可能出現(xiàn)-1,因此EOF定義為-1是合適的。當讀入的字符值等于-1(即EOF)時,表示讀入的已不是正常的字符而是文件結(jié)束符。但以上只適用于讀文本文件的情況?,F(xiàn)在ANSIC已允許用緩沖文件系統(tǒng)處理二進制文件,而讀入某一個字節(jié)中的二進制數(shù)據(jù)的值有可能是-1,而這又恰好是EOF的值。這就出現(xiàn)了需要讀入有用數(shù)據(jù)而卻被處理為“文件結(jié)束”的情況。為了解決這個問題,ANSIC提供一個feof函數(shù)來判斷文件是否真的結(jié)束。 feof(fp)用來測試fp所指向的文件當前狀態(tài)是否“文件結(jié)束”。如果是文件結(jié)束,函數(shù)feof(fp)的值為1(真),否則為0(假)。feof()判斷文件是否結(jié)束函數(shù)注意:EOF不是可輸出字符,feof()判斷文件是否結(jié)束函數(shù)如: while(!feof(fp)) { c=fgetc(fp); …}feof()判斷文件是否結(jié)束函數(shù)如:fputc和fgetc舉例例12.1從鍵盤輸入一些字符,逐個把它們送到磁盤上去,直到輸入一個“#”為止。源碼參見12-1.c例12.2將一個磁盤文件中的信息復(fù)制到另一個磁盤文件中。源碼參見12-2\a.c使用命令行方式輸入兩個文件名;源碼參見12-2\b.cfputc和fgetc舉例例12.1從鍵盤輸入一些字符,逐fread和fwrite函數(shù)ANSIC標準提出設(shè)置兩個函數(shù)(fread和fwrite),用來讀寫一個數(shù)據(jù)塊。它們的一般調(diào)用形式為 fread(buffer,size,count,fp); fwrite(buffer,size,count,fp);其中:buffer:是一個指針。對fread來說,它是讀入數(shù)據(jù)的存放地址。對fwrite來說,是要輸出數(shù)據(jù)的地址(以上指的是起始地址)。size:要讀寫的字節(jié)數(shù)。count:要進行讀寫多少個size字節(jié)的數(shù)據(jù)項。fp:文件型指針。如果fread或fwrite調(diào)用成功,則函數(shù)返回值為count的值,即輸入或輸出數(shù)據(jù)項的完整個數(shù)。fread和fwrite函數(shù)ANSIC標準提出設(shè)置兩個函數(shù)fread和fwrite函數(shù)如果文件以二進制形式打開,用fread和fwrite函數(shù)就可以讀寫任何類型的信息,如: fread(f,4,2,fp);其中f是一個實型數(shù)組名。一個實型變量占4個字節(jié)。這個函數(shù)從fp所指向的文件讀入2次(每次4個字節(jié))數(shù)據(jù),存儲到數(shù)組f中。fread和fwrite函數(shù)如果文件以二進制形式打開,用frfread和fwrite函數(shù)如果有一個如下的結(jié)構(gòu)體類型: structstudent-type { charname[10]; intnum; intage; charaddr[30]; }stud[40];假設(shè)學(xué)生的數(shù)據(jù)已存放在磁盤文件中,可以用下面的for語句和fread函數(shù)讀入40個學(xué)生的數(shù)據(jù): for(i=0;i<40;i++) { fread(&stud[i],sizeof(structstudent-type),1,fp); }同樣,以下for語句和fwrite函數(shù)可以將內(nèi)存中的學(xué)生數(shù)據(jù)輸出到磁盤文件中去: for(i=0;i<40,i++) { fwrite(&stud[i],sizeof(structstudent-type),1,fp); }fread和fwrite函數(shù)如果有一個如下的結(jié)構(gòu)體類型:fread和fwrite函數(shù)舉例例12.3從鍵盤輸入4個學(xué)生的有關(guān)數(shù)據(jù),然后把它們轉(zhuǎn)存到磁盤文件上去。源碼參見12-3fread和fwrite函數(shù)舉例例12.3從鍵盤輸入4個學(xué)其它讀寫函數(shù)自學(xué)。其它讀寫函數(shù)自學(xué)。(五)文件的定位(五)文件的定位文件中有一個位置指針,指向當前讀寫的位置。如果順序讀
溫馨提示
- 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)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 健康生活-快樂生活課件
- 2024年水利管理及技術(shù)咨詢服務(wù)項目投資申請報告代可行性研究報告
- 虎丘區(qū)工程監(jiān)理管理辦法
- 融媒體團隊管理辦法細則
- 衡水市藥品安全管理辦法
- 行業(yè)稅收網(wǎng)格化管理辦法
- 裝修貸資金管理暫行辦法
- 西安疫情中風(fēng)險管理辦法
- 規(guī)范新聞記者證管理辦法
- 證監(jiān)會投資平臺管理辦法
- 水利工程施工監(jiān)理規(guī)范(SL288-2014)用表填表說明及示例
- 醫(yī)療責(zé)任組長競聘
- 投標貨物包裝、運輸方案
- 抽水蓄能電站地下廠房系統(tǒng)開挖工程施工方案
- 國家開放大學(xué)《建筑力學(xué)》形成性作業(yè)1-4參考答案
- 流浪未成年人救助保護中心建設(shè)標準
- 2025數(shù)學(xué)步步高大一輪復(fù)習(xí)講義人教A版復(fù)習(xí)講義含答案
- 高中英語單詞構(gòu)詞法(完整版)
- PLM模塊業(yè)務(wù)流程圖
- 專題02《物態(tài)變化》壓軸培優(yōu)題型訓(xùn)練【十三大題型】(原卷版)
- 大學(xué)生科研訓(xùn)練與論文寫作全套教學(xué)課件
評論
0/150
提交評論