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

下載本文檔

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

文檔簡介

第10章文件10.1文件概述10.2文件的打開與關(guān)閉10.3文件的讀/寫操作10.4文件檢測函數(shù)10.5文件的定位10.6程序舉例習(xí)題10

本章學(xué)習(xí)要求:

1.了解文件的分類,了解文件函數(shù)使用時包含的頭文件。

2.掌握文件類型指針的定義,掌握文件打開與關(guān)閉函數(shù)的使用,掌握文件讀/寫操作函數(shù)的使用,掌握文件定位函數(shù)的使用,了解文件的檢索。

在前面所學(xué)的程序中,所有的程序都只能在運行時輸入信息以及顯示執(zhí)行的結(jié)果,卻不能將一次輸入多次使用,并且又不能將執(zhí)行的結(jié)果保存起來以供查看,例如,在創(chuàng)建鏈表的實例中每次運行時必須輸入一次鏈表中所有元素的信息,無法保存下來,同時對經(jīng)過處理(如插入元素)的鏈表結(jié)果也無法保存下來。并且在運行時如果需要輸入大量的數(shù)據(jù),在程序調(diào)試過程中也是比較麻煩的。因此,這就需要學(xué)習(xí)使用C語言編程對文件進(jìn)行訪問。

10.1.1文件的概念與分類

文件(file)在程序設(shè)計中是一個比較重要的概念。一般來說,文件就是指存儲在外存儲器上數(shù)據(jù)的集合。每個文件都有一個屬于自己的名字,稱為文件名。文件名是讀取文件的依據(jù),也是標(biāo)識文件的方式,就像我們?nèi)说拿质敲總€人的標(biāo)識一樣。操作系統(tǒng)就是通過文件名對各種文件進(jìn)行存取和處理的,即“按名存取”。10.1文件概述

1.文件的分類

根據(jù)文件中數(shù)據(jù)的存儲形式,一般可以將文件分成文本文件和二進(jìn)制文件兩種。

文本文件又稱為ASCII碼文件。在這種文件中是以字符為單位進(jìn)行存放的,每個字節(jié)存放一個字符的ASCII碼值(取值范圍0~127)。例如,一個整數(shù)3267,它是由4個數(shù)字字符組成,在文本文件中需要用4個字節(jié)來存放4個數(shù)字字符,如圖10.1(a)所示。二進(jìn)制文件是以二進(jìn)制位(bit)為單位的,數(shù)據(jù)按其在內(nèi)存中的存儲形式直接存放到文件中,即在二進(jìn)制文件中,數(shù)據(jù)與該數(shù)據(jù)的二進(jìn)制形式是一致的,其中的一個字節(jié)并不代表一個字符。例如,同樣的一個整數(shù)3267,化成二進(jìn)制數(shù)為110011000011,因此,它在二進(jìn)制文件中只需要占2個字節(jié),如圖10.1(b)所示。

圖10.1整數(shù)3267在文件中的存儲形式

2.緩沖文件系統(tǒng)

C語言編譯系統(tǒng)對文件的處理有兩種方式,分別采用緩沖文件系統(tǒng)方式與非緩沖文件系統(tǒng)方式進(jìn)行。

緩沖文件系統(tǒng)是指系統(tǒng)自動地為正在被使用的文件在內(nèi)存中開辟一個緩沖區(qū)。當(dāng)需要向外存中的文件輸出數(shù)據(jù)時,必須先將數(shù)據(jù)送到為該文件開辟的緩沖區(qū)中,當(dāng)緩沖區(qū)充滿后才一起送到外存中。當(dāng)需要對外存中的文件讀入數(shù)據(jù)時,也先從外存一次將一批數(shù)據(jù)讀入緩沖區(qū)(將緩沖區(qū)充滿或?qū)⑺璧臄?shù)據(jù)全部讀入),然后再從緩沖區(qū)中將數(shù)據(jù)逐個讀入。在這種文件系統(tǒng)中,對文件的輸入/輸出是通過為該文件開辟的緩沖區(qū)進(jìn)行的。緩沖文件系統(tǒng)又稱為高級文件系統(tǒng)。非緩沖文件系統(tǒng)是指系統(tǒng)不自動為文件開辟緩沖區(qū),而是由用戶程序自己為文件設(shè)定緩沖區(qū)。非緩沖文件系統(tǒng)又稱為低級文件系統(tǒng)。

ANSIC標(biāo)準(zhǔn)采用的是緩沖文件系統(tǒng),對文件的操作都通過標(biāo)準(zhǔn)庫函數(shù)來實現(xiàn)。

3.文件操作的步驟

程序?qū)ξ募M(jìn)行操作時,一般要經(jīng)過以下三個步驟:

(1)打開文件。用標(biāo)準(zhǔn)庫函數(shù)fopen()打開文件,它通知編譯系統(tǒng)三個信息:需要打開的文件名;使用文件的方式(讀還是寫等);使用的文件指針。編譯系統(tǒng)將需要的文件調(diào)入內(nèi)存緩沖區(qū)。

(2)文件讀寫。用文件輸入或輸出函數(shù)對文件進(jìn)行讀寫,這些輸入或輸出函數(shù)與前面介紹的標(biāo)準(zhǔn)輸入與輸出函數(shù)在功能上有相似之處,但在使用上又不相同。

(3)關(guān)閉文件。文件讀寫完畢,用標(biāo)準(zhǔn)庫函數(shù)fclose()關(guān)閉文件。它的主要功能是將數(shù)據(jù)從內(nèi)存真正寫入磁盤(否則數(shù)據(jù)可能還在內(nèi)存緩沖區(qū)中),切斷文件指針與文件名之間的聯(lián)系,釋放文件指針。如果文件使用完后不關(guān)閉可能會造成數(shù)據(jù)的丟失。因此,我們在使用文件時,如果文件不再使用時,及時關(guān)閉文件是一個好習(xí)慣。當(dāng)然,當(dāng)程序正常運行結(jié)束時,系統(tǒng)也會自動關(guān)閉所有已經(jīng)打開的文件。10.1.2文件類型指針

在進(jìn)行文件操作時,要用文件指針。文件指針用來指向緩沖區(qū)中文件當(dāng)前操作的位置,當(dāng)文件指針與某個文件連接后,用戶就通過文件指針而不是文件名來存取文件。文件指針是由系統(tǒng)在頭文件stdio.h中定義的結(jié)構(gòu)類型,類型名為FILE,其成員分別用來存放文件名、文件狀態(tài)標(biāo)志及緩沖區(qū)大小等信息。有興趣的讀者可以到TurboC編譯系統(tǒng)的include文件夾中參閱stdio.h文件內(nèi)容,通常情況下不用了解其中的細(xì)節(jié),只要能用類型名FILE來定義文件指針就可以了。定義文件指針的一般形式如下:

FILE*指針變量名表列;

其中,指針變量名表列是指可以一次定義一個到多個文件指針,每個文件指針可以用于存放一個文件緩沖區(qū)的首地址。例如:

FILE*fp1,*fp2;

定義了名為fp1和fp2的兩個文件指針,可以由fopen()函數(shù)將它們分別指向一個文件。

注意:一個文件指針只能指向一個文件。如果想打開幾個文件,就應(yīng)該有幾個文件指針。

10.2.1文件的打開

打開文件要用庫函數(shù)fopen(),其調(diào)用的一般格式如下:

FILE*fp;/*也可以用其他文件指針變量名,這里用fp作為文件指針變量名*/

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

從上述格式可以看出,要想打開一個文件,必須先為該文件定義一個文件類型指針,然后才能用fopen()函數(shù)打開文件。10.2文件的打開與關(guān)閉

fopen()函數(shù)在調(diào)用時有兩個參數(shù):“文件名”與“文件使用方式”,它們都是字符串。其中“文件名”是要打開的文件的名字,當(dāng)然可以帶文件路徑,但在文件路徑中的“\”必須使用轉(zhuǎn)義字符,例如:fopen("c:\\tc20\\t.txt","w")就是正確打開帶路徑文件的方式;“文件使用方式”規(guī)定了打開文件的目的,如表10.1所示。

fopen()函數(shù)的主要功能是為需要打開的文件分配一個緩沖區(qū),并返回該緩沖區(qū)的首地址。如果文件打開不成功(可能找不到對應(yīng)的文件),則返回NULL(或0),NULL是一個空指針值,也是由stdio.h頭文件定義的。

表10.1文件使用方式為確保文件的正常操作,有必要在程序中檢測文件是否正常打開,即打開文件的操作是否成功。常用下面的程序段來打開文件:

if((fp=fopen("filename","w"))==NULL)

{printf("Cannotopenfile!\n");exit(1);}

這樣,當(dāng)文件不能正常打開時,屏幕提示“Cannotopenfile!”,程序運行終止,返回操作系統(tǒng)。exit()函數(shù)的功能是終止程序運行,關(guān)閉文件并返回操作系統(tǒng),它也是在stdio.h頭文件中定義的;如果文件打開成功,程序就可以繼續(xù)執(zhí)行。10.2.2文件的關(guān)閉

對文件操作完成后,必須關(guān)閉文件,以保證本次文件操作有效。文件關(guān)閉使用fclose()標(biāo)準(zhǔn)庫函數(shù),其一般形式如下:

fclose(文件指針變量名);

例如,要關(guān)閉前面的文件指針變量fp指向的文件,可以使用fclose(fp);來關(guān)閉。若關(guān)閉成功則返回0,否則返回EOF(即-1)??梢杂胒error()函數(shù)來測試。

10.3.1文件讀函數(shù)

對文件進(jìn)行讀操作,是指從外存儲器的文件中向程序輸入數(shù)據(jù)。

在C語言中,讀文件的函數(shù)主要有:fgetc()、fread()、fscanf()。

10.3文件的讀/寫操作

1.?fgetc()函數(shù)

fgetc()函數(shù)的功能是:從指定的文件讀入一個字符。其一般格式如下:

charc;

c=fgetc(fp);

其中:fp是已經(jīng)定義過的文件指針變量,該函數(shù)從fp指向的文件中的當(dāng)前位置讀取一個字符,并將該字符的ASCII碼值保存到字符變量c中。

當(dāng)讀到文件末尾或讀取出錯時,該函數(shù)返回一個文件結(jié)束標(biāo)志EOF(-1)。因為字符的ASCII碼為非負(fù)值,所以可以用EOF(-1)作為結(jié)束標(biāo)志,即當(dāng)讀入的字符值等于EOF時表示文件已經(jīng)結(jié)束。

2.?fgets()函數(shù)

fgets()函數(shù)的功能是:從指定的文件中讀出一個字符串,其一般格式如下:

fgets(s,n,fp);

其中:s可以是字符型數(shù)組名或字符串指針,n是指定讀入的字符個數(shù),fp是文件指針變量。使用上面格式最多從文件中讀出n-1個字符,并將讀出的字符串存入指針s。當(dāng)函數(shù)讀取的字符達(dá)到指定的個數(shù)(n-1個),或者接收到換行符,再或者接收到文件結(jié)束標(biāo)志EOF時,將在讀取的字符后面自動添加一個字符串結(jié)束標(biāo)志'\0';若有換行符,則將換行符保留在'\0'字符之后;若有EOF,則不保留文件結(jié)束標(biāo)志EOF。

該函數(shù)如果執(zhí)行成功,返回讀取的字符串指針;如果失敗,則返回空指針,此時,s中的內(nèi)容不確定。

3.?fread()函數(shù)

fread()函數(shù)的功能是:從指定的文件中讀入一組數(shù)據(jù)。其一般格式如下:

fread(buffer,size,count,fp);

其中:buffer表示存放讀入數(shù)據(jù)的內(nèi)存首地址,比如數(shù)組名;size表示每個數(shù)據(jù)項的字節(jié)數(shù);count表示數(shù)據(jù)項個數(shù);fp表示文件指針變量。

本函數(shù)是從fp指向的文件中,一次讀出長度為size字節(jié)的count個數(shù)據(jù)項,然后存放在buffer中。在讀出過程中,自動把文件中的回車符、表示制表符和換行符的轉(zhuǎn)義序列轉(zhuǎn)換成換行符。該函數(shù)如果執(zhí)行成功,則返回實際讀出的數(shù)據(jù)項個數(shù);如果讀出數(shù)據(jù)項比調(diào)用中所需數(shù)據(jù)項少,則出錯。關(guān)于出錯的判斷見下一節(jié)的介紹。

4.?fscanf()函數(shù)

fscanf()函數(shù)的功能是:從指定的文件中格式化讀取數(shù)據(jù)。其一般格式如下:

fscanf(文件指針變量,格式控制串,地址表);

本函數(shù)與格式輸入函數(shù)scanf()很相似,其中,“格式控制串”和“地址表”的用法與scanf()函數(shù)相同。它們的區(qū)別就在于,scanf()函數(shù)是從鍵盤輸入數(shù)據(jù),而fscanf()函數(shù)是從文件讀入數(shù)據(jù),因此在fscanf()函數(shù)參數(shù)中多了一個文件指針,用于指出從哪個文件讀入數(shù)據(jù)。該函數(shù)如果執(zhí)行成功,則返回讀取項目的個數(shù);如果遇到文件末尾,則返回EOF;如果賦值失敗,則返回0。10.3.2文件寫函數(shù)

對文件進(jìn)行寫操作,就是將程序中處理好的數(shù)據(jù)寫到指定的文件中。

在C語言中,讀文件的函數(shù)主要有fputc()、fputs()、fwrite()和fprintf()。

1.?fputc()函數(shù)

fputc()函數(shù)的功能是:將一個字符寫到指定的文件中。其一般格式如下:

fputc(c,fp);

該函數(shù)將字符變量c中的字符碼值寫入fp指向的文件當(dāng)前位置。如果寫成功,則返回寫入文件的字符,否則返回EOF。

例10.1

先從鍵盤輸入一串字符寫入文件t1.txt中(當(dāng)輸入“#”時結(jié)束),并將文件t1.txt中的信息復(fù)制到文件t2.txt,最后在屏幕上顯示出文件t2.txt中的內(nèi)容。

問題分析:本例可以分成三步進(jìn)行,第一步:從鍵盤輸入一串字符寫入文件t1.txt,在進(jìn)行第二步前,必須將文件t1.txt的文件指針fp1復(fù)位到文件開頭(可以使用rewind()函數(shù)或?qū)⑽募P(guān)閉,再打開);第二步:從文件t1.txt將內(nèi)容復(fù)制到文件t2.txt中,再將文件t2.txt的文件指針fp2復(fù)位到文件開頭;第三步:將文件t2.txt的內(nèi)容顯示到屏幕上。程序如下:

#include<stdio.h>

main()

{charc;

FILE*fp1,*fp2;

if((fp1=fopen("t1.txt","w+"))==NULL)

{printf("Cannotopent1.txt!\n");exit(1);}

if((fp2=fopen("t2.txt","w+"))==NULL)

{printf("Cannotopent2.txt!\n");exit(1);}

while((c=getchar())!='#')/*從鍵盤輸入字符存入文件t1.txt中*/

fputc(c,fp1);

rewind(fp1);/*將文件t1.txt的文件指針移到文件開頭*/

while((c=fgetc(fp1))!=EOF) /*將文件t1.txt的內(nèi)容復(fù)制到文 件t2.txt*/

fputc(c,fp2);

rewind(fp2);

while((c=fgetc(fp2))!=EOF) /*將文件t2.txt中的內(nèi)容輸出到 屏幕上*/

putchar(c);

fclose(fp1);fclose(fp2);

}

2.?fputs()函數(shù)

fputs()函數(shù)的功能是:將一個字符串寫入指定的文件中。其一般格式如下:

fputs(s,fp);

其中,s可以是字符型數(shù)組名或字符串指針,fp是文件指針變量。

使用上面格式可以將字符串寫入由fp指向的文件中,字符串結(jié)束標(biāo)志'\0'字符不寫入。

該函數(shù)如果執(zhí)行成功,則返回寫入的最后一個字符;如果失敗,則返回EOF。

例10.2

將字符串寫入文件和讀出文件。

#include<stdio.h>

#include<string.h>

main()

{charstr[80],str1[80];

FILE*fp;

if((fp=fopen("t.txt","w+"))==NULL)

{printf("Cannotopent.txt!\n");exit(1);}

gets(str);

fputs(str,fp); /*將字符串寫入文件中*/

rewind(fp); /*將文件指針復(fù)位到文件開頭*/

fgets(str1,strlen(str)+1,fp); /*從文件中將字符串讀出*/

puts(str1); /*輸出到屏幕上*/

fclose(fp);

}

3.?fwrite()函數(shù)

fwrite()函數(shù)的功能是:將一組數(shù)據(jù)寫到指定的文件中。其一般格式如下:

fwrite(buffer,size,count,fp);

其中:buffer 存放讀入數(shù)據(jù)的內(nèi)存首地址,比如數(shù)組名

size每個數(shù)據(jù)項的字節(jié)數(shù)

count數(shù)據(jù)項個數(shù)

fp文件指針變量本函數(shù)是向fp指向的文件中一次寫入一個由buffer指向的數(shù)據(jù)塊,該數(shù)據(jù)塊共有count個數(shù)據(jù)項,每個數(shù)據(jù)項有size個字節(jié)。

該函數(shù)如果執(zhí)行成功,則返回實際寫入的數(shù)據(jù)項個數(shù);如果寫入的數(shù)據(jù)項比調(diào)用中所需數(shù)據(jù)項少,則出錯。關(guān)于出錯的判斷見下一節(jié)的介紹。

例10.3

記錄型信息的訪問。

在學(xué)習(xí)結(jié)構(gòu)體的時候我們就知道,真實的信息數(shù)據(jù)通常都是以記錄形式存在,而這種記錄可以通過結(jié)構(gòu)體來實現(xiàn),本例就是實現(xiàn)文件中記錄型信息的訪問。

程序如下:

#include<stdio.h>

voidput_in(); /*聲明函數(shù)*/

voidget_out(); /*聲明函數(shù)*/

structstudent /*定義結(jié)構(gòu)體類型*/

{charname[10];

intscore;

}

main()

{

printf("Recorddataaccess!\n\n");

put_in(); /*調(diào)用文件寫入函數(shù)*/

get_out(); /*調(diào)用文件讀出函數(shù)*/

}

/*寫入文件函數(shù)*/

voidput_in()

{FILE*fp;

structstudentstud[]={{"張三",67},{"李四",78},{"王五",89},{"田三",92},{"趙七",54},

{"劉八",48}};

if((fp=fopen("stud.dat","wb"))==NULL)

{printf("Cannotcreatstud.dat!\n");exit(1);}

fwrite(stud,sizeof(structstudent),6,fp); /*將結(jié)構(gòu)體數(shù)組寫入 文件中*/

fclose(fp);

printf("OK!\n");

}

/*讀出文件數(shù)據(jù)函數(shù)*/

voidget_out()

{FILE*fp;

structstudentstud[6];

inti;

if((fp=fopen("stud.dat","rb"))==NULL)

{printf("Cannotopenstud.dat!\n");exit(1);}

fread(stud,sizeof(structstudent),6,fp); /*從文件中讀出數(shù)據(jù) 放入結(jié)構(gòu)體數(shù)組*/

printf("姓名\t成績\n");

printf("----\t----\n");

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

printf("%s\t%d\n",stud[i].name,stud[i].score);

printf("\n");

fclose(fp);

}程序運行結(jié)果如下:

Recorddataaccess!

OK!

姓名成績

--------

張三67

李四78

王五89

田三92

趙七54

劉八48

4.?fprintf()函數(shù)

fprintf()函數(shù)的功能是:向指定的文件中格式化寫入數(shù)據(jù)。其一般格式如下:

fprintf(文件指針變量,格式控制串,輸出表);

其中:輸出表是由表達(dá)式組成的表列。

本函數(shù)與格式輸出函數(shù)printf()很相似,其中“格式控制串”和“輸出表”的用法與printf()函數(shù)相同。它們的區(qū)別就在于,printf()函數(shù)是將數(shù)據(jù)輸出到顯示屏幕上,而fprintf()函數(shù)是將數(shù)據(jù)輸出到文件中,因此在fprintf()函數(shù)參數(shù)中多了一個文件指針,用于指出將數(shù)據(jù)輸出到哪個文件中。

fprintf()函數(shù)與fscanf()函數(shù)是對應(yīng)的,最好結(jié)合使用。即使用fprintf()函數(shù)向文件中格式化寫入數(shù)據(jù),而用fscanf()函數(shù)將數(shù)據(jù)從文件中格式化讀出。因此,在使用fprintf()函數(shù)時,其格式應(yīng)與用fscanf()函數(shù)將數(shù)據(jù)從該文件讀出時的格式一致,否則會導(dǎo)致讀/寫錯誤。

該函數(shù)如果執(zhí)行成功,則返回實際寫入文件的字符個數(shù);若出現(xiàn)錯誤,則返回負(fù)數(shù)。

例10.4

從鍵盤輸入一個整數(shù)、一個實數(shù)、一個字符,將其寫入文件ttt.txt,再將其從文件中讀出,輸出到屏幕上。

問題分析:本例可以先分別定義一個整型、實型、字符型變量,再從鍵盤各輸入一個值,使用fprintf()函數(shù)將三個值按相應(yīng)格式寫入到文件ttt.txt中,再使用fscanf()函數(shù)從文件中讀出,并使用格式輸出printf()函數(shù)輸出到屏幕上。程序如下:

#include<stdio.h>

main()

{inta,a1;floatb,b1;charc,c1;

FILE*fp;

if((fp=fopen("ttt.txt","w+"))==NULL)

{printf("Cannotopenfile!\n");exit(1);}

printf("Pleasea,b,c:");

scanf("%d,%f,%c",&a,&b,&c);

fprintf(fp,"%d,%f,%c",a,b,c);

/*rewind(fp);*//*將文件指針置于文件開頭位置*/

fclose(fp);

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

fscanf(fp,"%d,%f,%c",&a1,&b1,&c1);

printf("%d,%f,%c\n",a,b,c);

printf("%d,%f,%c\n",a1,b1,c1);

}注意:程序中將三個數(shù)寫入文件后,將文件關(guān)閉,再以只讀的方式打開,并且重新格式化讀出數(shù)據(jù)。如果不這樣做(寫入文件后馬上讀出)就會造成讀出的數(shù)據(jù)不對,為什么呢?因為我們向文件中寫完數(shù)據(jù)后,文件指針此時停留在文件尾,如果馬上讀取就會從文件指針當(dāng)前位置向后讀,顯然讀取的數(shù)據(jù)不對。要想解決這樣的問題,可以使用兩種方法:①使用rewind(fp)函數(shù)將文件指針移到文件開頭位置;②先將文件關(guān)閉,再以只讀的方式打開。

文件檢測函數(shù)用于檢測文件指針是否到文件末尾,或文件讀/寫操作中是否出現(xiàn)錯誤等情況,以便能正確地進(jìn)行文件的存取。10.4文件檢測函數(shù)

1.?feof()函數(shù)

feof()函數(shù)用于二進(jìn)制文件結(jié)束檢測。對于文本文件,通??捎肊OF作為結(jié)束標(biāo)志,EOF的值為-1,因為任何ASCII碼都不可能取負(fù)值,所以它在文本文件中不會產(chǎn)生沖突。而對于二進(jìn)制文件,-1可能是字節(jié)數(shù)據(jù)的值,所以EOF不能作為二進(jìn)制文件的結(jié)束標(biāo)志。因此,二進(jìn)制文件結(jié)束的判斷只能使用feof()函數(shù)來完成,它的一般格式如下:

feof(fp);

其中:fp是已定義過的文件指針。該函數(shù)用于檢測文件是否結(jié)束,如果結(jié)束則返回非0值;否則返回0值。

2.?ferror()函數(shù)

ferror()函數(shù)用于檢測文件讀/寫時是否發(fā)生錯誤,其一般格式如下:

ferror(fp);

其中:fp是已定義過的文件指針。如果在文件讀/寫過程中未發(fā)生錯誤,則返回0值;否則,返回非0值。

3.?clearerr()函數(shù)

clearerr函數(shù)用于將文件的出錯標(biāo)志和文件結(jié)束標(biāo)志置0。當(dāng)調(diào)用的文件輸入或輸出函數(shù)出錯時,ferror()函數(shù)給出非0的標(biāo)志,并一直保持此非0值,直到使用clearerr()函數(shù)或rewind()函數(shù)時才重新置0。其一般格式如下:

clearerr(fp);

其中:fp是已定義過的文件指針。使用clearerr()函數(shù)可以及時清除出錯標(biāo)志。

為了正確地對文件進(jìn)行讀/寫操作,在一個文件被打開后,系統(tǒng)就為該文件設(shè)置一個讀/寫指針,用于指示當(dāng)前讀/寫的位置。當(dāng)進(jìn)行一次讀/寫操作后,文件的讀/寫指針位置自動向后移動。每次打開文件總是從文件開始位置進(jìn)行讀/寫操作的,但有時文件經(jīng)過讀/寫后,還需要回到文件頭;或有時需要直接修改文件中的某個部分內(nèi)容。對于這樣的情況,最好使用文件的定位函數(shù)。10.5文?件?的?定?位文件的定位函數(shù)主要有以下幾種。

1.?rewind()函數(shù)

有時文件經(jīng)過讀/寫后,還需要回到文件頭以便訪問,而此時卻因為前面的文件操作使文件指針移動到文件的其他位置,這時就需要重置文件指針使其回到文件頭。

rewind()函數(shù)的功能是:將文件指針重置于文件開頭位置。其一般格式如下:

rewind(fp);

其中:fp是已定義過的文件指針。

2.?fseek()函數(shù)

fseek()函數(shù)的主要功能是:將文件的讀/寫指針移動到指定的位置。其一般格式如下:

fseek(fp,偏移量,起始位置);

其中:fp是已定義過的文件指針;起始位置是指移動文件讀/寫指針的參考位置,它有以下三個值:

SEEK_SET或0

表示文件開頭

SEEK_CUR或1表示當(dāng)前讀/寫的位置

SEEK_END或2表示文件末尾偏移量是相對“起始位置”的偏移字節(jié)數(shù),它要求是long型數(shù)據(jù)(可正可負(fù))。例如:

fseek(fp,100L,1);/*將文件指針從當(dāng)前讀/寫位置向文件尾方向 移動100個字節(jié)*/

fseek(fp,-10L,2);/*將文件指針從文件尾向文件頭方向移動10 個字節(jié)*/

fseek(fp,100L,0);/*將文件指針從文件頭向文件尾方向移動100 個字節(jié)*/

fseek()函數(shù)的意義在于:可以把文件指針移到文件的任何位置,實現(xiàn)對文件的隨機(jī)讀/寫操作。

3.?ftell()函數(shù)

在程序執(zhí)行中,如果想要獲取文件指針的當(dāng)前位置,可以使用ftell()函數(shù)來完成。

ftell()函數(shù)的功能是:返回文件的當(dāng)前讀/寫位置。其一般格式如下:

ftell(fp);

其中:fp是已定義過的文件指針。該函數(shù)如果執(zhí)行成功,則返回相對于文件頭的位移量(字節(jié)數(shù)),否則返回-1L。

例10.5

設(shè)有結(jié)構(gòu)體數(shù)組定義如下:

structstudent

{charname[10];

charsection[20];

intage,score;

}st[]={{"王小二","商學(xué)院",23,78},{"阮小二","理學(xué)院",22,80},{"阮小七",

"信息院",

21,65},{"孫二","人文學(xué)院",23,58},{"張三","農(nóng)學(xué)院",22,92}};10.6程序舉例編寫如下程序:首先建立名為my_stud.dat的二進(jìn)制文件,用于保存給結(jié)構(gòu)體數(shù)組所賦的值;然后對上述學(xué)生數(shù)據(jù)按成績排序(降序),并將排完序的數(shù)據(jù)添加到原文件,并顯示到屏幕上。程序如下:

#include<stdio.h>

structstudent

{charname[10];

charsection[20];

intage,score;

}st[10]={{"王小二","商學(xué)院",23,78},{"阮小二","理學(xué)院",22,80},{"阮小七","信息院",

21,65},{"孫二","人文學(xué)院",23,58},{"張三","農(nóng)學(xué)院",22,92}},work;

voidsort()

{inti,j;

FILE*fp;

if((fp=fopen("my_stud.dat","rb"))==NULL)

{printf("Filecannotopen!\n");exit(1);}

for(i=0;i<5;i++) /*將數(shù)據(jù)從文件中讀出*/

fread(&st[i],sizeof(structstudent),1,fp);

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

for(j=i+1;j<5;j++)

if(st[i].score<st[j].score)

{work=st[i];

st[i]=st[j];

st[j]=work;

}

fclose(fp);

fp=fopen("my_stud.dat","ab");

fseek(fp,0,SEEK_END);

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

fwrite(&st[i],sizeof(structstudent),1,fp);

fclose(fp);

}

main()

{intk;

FILE*fp;

if((fp=fopen("my_stud.dat","wb"))==NULL)

{printf("Filecannotopen!\n");exit(1);}

for(k=0;k<5;k++) /*將數(shù)據(jù)寫入文件*/

fwrite(&st[k],sizeof(structstudent),1,fp);

fclose(fp);

sort();

fp=fopen("my_stud.dat","rb");

clrscr();

printf("-----------排序前數(shù)據(jù)------------\n");

for(k=0;k<10;k++) /*將數(shù)據(jù)從文件中讀出*/

{fread(&st[k],sizeof(structstudent),1,fp);

printf("%s,%s,%d,%d\n",st[k].name,st[k].section,st[k].age,st[k].score);

if(k==4)

printf("-----------排序后數(shù)據(jù)-------------\n");

}

}程序運行結(jié)果如下:

-----------排序前數(shù)據(jù)-------------

王小二,商學(xué)院,23,78

阮小二,理學(xué)院,22,80

阮小七,信息院,21,65

孫二,人文學(xué)院,23,58

張三,農(nóng)學(xué)院,22,92

-----------排序后數(shù)據(jù)-------------

張三,農(nóng)學(xué)院,22,92

阮小二,理學(xué)院,22,80

王小二,商學(xué)院,23,78

阮小七,信息院,21,65

孫二,人文學(xué)院,23,58

例10.6

建立my_stud.dat文件,將初始化的結(jié)構(gòu)化數(shù)組中的數(shù)據(jù)放入該文件中,并查詢出成績不及格的學(xué)生和成績優(yōu)良(>=80分)的學(xué)生。

程序如下:

/*成績查詢程序*/

#include<stdio.h>

structstudent

{charname[10];

charsection[20];

intage,score;

}st[]={{"王小二","商學(xué)院",23,78},{"阮小二","理學(xué)院",22,80},{"阮小七","信息院",21,65},

{"孫二","人文學(xué)院",23,58},{"張三","農(nóng)學(xué)院",22,92}};

main()

{FILE*fp;intk;

printf("成績查詢\n\n");

if((fp=fopen("my_stud.dat","wb"))==NULL)

{printf("Filecannotopen!\n");exit(1);}

for(k=0;k<5;k++) /*將數(shù)據(jù)寫入文件中*/

fwrite(&st[k],sizeof(structstudent),1,fp);

fclose(fp);

if((fp=fopen("my_stud.dat","rb"))==NULL)

{printf("Filecannotopen!\n");exit(1);}

for(k=0;k<5;k++) /*將數(shù)據(jù)從文件中讀出*/

fread(&st[k],sizeof(structstudent),1,fp);

k=0;printf("不及格者姓名\t成績\n");

while(!feof(fp))

{fseek(fp,(long)sizeof(structstudent)*k,SEEK_SET);

fread(&st,sizeof(structstudent),1,fp);

if(st[k].score<60&&!feof(fp))

printf("%s\t\t%d\n",st[k].name,st[k].score);

k++;

}

rewind(fp);

k=0;printf("優(yōu)良者姓名\t成績\n");

while(!feof(fp))

{fseek(fp,(long)sizeof(structstudent)*k,SEEK_SET);

fread(&st,sizeof(structstudent),1,fp);

if(st[k].score>=80&&!feof(fp))

printf("%s\t\t%d\n",st[k].name,st[k].score);

k++;

}

fclose(fp);

}程序運行結(jié)果如下:

成績查詢

不及格者姓名成績

孫二 58

優(yōu)良者姓名成績

阮小二 80

張三 92

例10.7

文本文件查看程序。

請完成類似DOS下type命令的功能,用于查看指定文本文件的內(nèi)容。查看的格式如:L10-07<文本文件名>。

/*L10-07.c*/

/*文本文件查看程序L10-07.c*/

#include<stdio.h>

main(intargc,char*argv[])

/*變量argc用來檢測輸入的參數(shù)項 目個數(shù),argv[]為一個字符指針數(shù)組,用于存放參數(shù)*/

{FILE*fp;

charletter[256];/*從文件中得到的數(shù)據(jù)將要存入的數(shù)組*/

intc,i;

if(argc<2)

{printf("命令的格式應(yīng)是:L10-07<文件名>\n");exit(1);}

if((fp=fopen(argv[1],"r"))==NULL)

{printf("不能打開%s文件!\n",argv[1]);exit(1);}

do

{i=0;

while((c=fgetc(fp))!=EOF) /*從文件中讀出字符,并放到 字符數(shù)組letter中*/

{letter[i]=c;i++;

if(c=='\n')break;

}

letter[i]='\0';

printf("%s",letter); /*輸入字符數(shù)組*/

}while(c!=EOF);

fclose(fp);

}

說明:先將程序編譯成可執(zhí)行文件L10-07.exe,再在DOS提示符下輸入以下命令行:

L10-07L10-07.c

這樣可以得到本例的源程序文件。

一、選擇題

1.

C語言文件的組成成分是()。

A.記錄B.數(shù)據(jù)行C.數(shù)據(jù)塊D.字符(字節(jié))系列

2.

C語言中,數(shù)據(jù)文件的存取方式為()。

A.只能順序存取

B.只能隨機(jī)存取(也叫直接存取)

C.可以順序存取和隨機(jī)存取

D.只能從文件的開頭進(jìn)行存取習(xí)題10

3.以C語言中,用“a”方式打開一個已含有10個字符的文本文件,并寫入了8個新字符,則該文件中存放的字符是()。

A.新寫入的8個字符

B.新寫入的8個字符覆蓋原有字符中的前8個字符,保留原有的后2個字符

C.原有的10個字符在前,新寫入的8個字符在后

D.新寫入的8個字符在前,原有的10個字符在后

4.當(dāng)已存在一個t.txt文件時,執(zhí)行函數(shù)fopen("t.txt","r+")的功能是()。

A.打開t.txt文件,清除原有內(nèi)容

B.打開t.txt文件,只能寫入新的內(nèi)容

C.打開t.txt文件,只能讀取原有的內(nèi)容

D.打開t.txt文件,可以讀取和寫入新的內(nèi)容

5.若用fopen()函數(shù)打開一個新的二進(jìn)制文件,該文件可以讀也可以寫,則文件的使用方式是()。

A.

"ab+"B.

"wb+"C.

"rb+"D.

"ab"

6.若用fopen()函數(shù)打開一個已存在的文件文件,保留該文件原有數(shù)據(jù)且可以讀也可以寫,則文件打開方式是()。

A.

"r+"B.

"w+"C.

"a+"D.

"a"

7.

fseek函數(shù)可以實現(xiàn)的操作是()。

A.改變文件位置指針的當(dāng)前位置B.文件的順序讀/寫

C.文件的隨機(jī)讀/寫

D.以上都不對

8.以下不能將文件指針移到文件開頭的函數(shù)是()。

A.

rewind(fp);

B.

fseek(fp,0,SEEK_SET);

C.

fseek(fp,-(long)ftell(fp),SEEK_CUR);

D.

fseek(fp,0,SEEK_END);

9.

fread(buf,64,2,fp)的功能是()。

A.從fp指向的文件中讀出整數(shù)64,并存放在buf中

B.從fp指向的文件中讀出整數(shù)64和2,并存放在buf中

C.從fp指向的文件中讀出64個字節(jié)的字符,并存放在buf中

D.從fp指向的文件中讀出2個64個字節(jié)的字符,并存放在buf中

10.檢測文件指針fp在文件頭的條件是()。

A.

fp==0 B.

ftell(fp)==0

C.

fseek(fp,0,SEEK_SET) D.

feof(fp)

11.

fgets(s,n,fp)函數(shù)的功能是從文件讀出字符串并存入內(nèi)存首地址s,以下敘述中正確的是()。

A.

n代表最少能讀出n個字符串

B.

n代表最多能讀出n個字符

C.

n代表最少能讀出n-1個字符串

D.

n代表最多能讀出n-1個字符

12.若fp是指向某文件的指針,且已讀到該文件的末尾,則函數(shù)feof(fp)的返回值是()。

A.

EOF B.-1 C.非0值 D.

NULL

13.執(zhí)行fseek(fp,-20L,1);后的結(jié)果是()。

A.將文件指針從當(dāng)前位置向文件末尾方向移動20字節(jié)

B.將文件指針從文件頭向文件末尾方向移動20字節(jié)

C.將文件指針從當(dāng)前位置向文件頭方向移動20字節(jié)

D.將文件指針從文件末尾向文件頭方向移動20字節(jié)

14.下列敘述中正確的是()。

A.

EOF只能作為二進(jìn)制文件的結(jié)束標(biāo)志,feof()只能用來判斷文本文件是否結(jié)束

B.

EOF只能作為文本文件的結(jié)束標(biāo)志,feof()只能用來判斷二進(jìn)制文件是否結(jié)束

C.

EOF可作為文本文件和二進(jìn)制文件的結(jié)束標(biāo)志,feof()只能用來判斷文本文件是否結(jié)束

D.

EOF只能作為文件文件的結(jié)束標(biāo)志,feof()則可以用來判斷文本文件和二進(jìn)制文件是否結(jié)束

15.若fp為文件指針,且文件已經(jīng)正確打開,則以下語句的輸出結(jié)果為()。

fseek(fp,0,SEEK_END);

n=ftell(fp);

printf("n=%d\n",n);

A.

fp所指文件的長度,以字節(jié)為單位

B.

fp所指文件的當(dāng)前位置,以比特為單位

C.

fp所指文件的長度,以比特為單位

D.

fp所指文件的當(dāng)前位置,以字節(jié)為單位

16.已知A盤根目錄下的一個文本數(shù)據(jù)文件data.dat中存儲了100個int型數(shù)據(jù),若需要修改該文件中已經(jīng)存在的若干個數(shù)據(jù)的值,只能調(diào)用一次fopen函數(shù),已有聲明語句“FILE*fp;”,則fopen函數(shù)的正確調(diào)用形式是()。

A.

fp=fopen("a:\\data.dat","r+");

B.

fp=fopen("a:\\data.dat","w+");

C.

fp=fopen("a:\\data.dat","a+");

D.

fp=fopen("a:\\data.dat","w");

17.已知有語句“FILE*fp;intx=123;fp=fopen("out.dat

","w");”,如果需要將變量x的值以文本形式保存到一個磁盤文件out.dat中,則以下函數(shù)調(diào)用形式中,正確的是()。

A.

fprintf("%d",x);

B.

fprintf(fp,"%d",x);

C.

fprintf("%d",x,fp);

D.

fprintf("out.dat","%d",x);

18.完成將文件指針fp重新指向文件開頭的函數(shù)是()。

A.

feof(fp) B.

rewind(fp)

C.

fseek(fp) D.

ftell(fp)

19.要打開一個已存在的非空文件“file”用于修改,正確的語句是()。

A.

fp=fopen("file","r");

B.

fp=fopen("file","a+");

C.

fp=fopen("file","w");

D.

fp=fopen("file","r+");

20.

fgets(str,n,fp)函數(shù)從文件中讀出一個字符串,以下正確的敘述是()。

A.字符串讀出后不會自動加入'\0'

B.

fp是file類型的指針

C.

fgets函數(shù)將讀出文件中最多n-1個字符

D.

fgets函數(shù)將讀出文件中最多n個字符

二、填空題

1.已知聲明語句:“FILE*fp1,*fp2;longa[2]={12345678,12345678};”,當(dāng)執(zhí)行了以下語句后,文件f1.dat和f2.dat長度分別為__________字節(jié)和_________字節(jié)。

fp1=fopen("f1.dat","w");fprintf(fp1,"%ld%ld",a[0],a[1]);fclose(fp1);

fp1=fopen("f2.dat","wb");fwrite(a,sizeof(long),2,fp2);fclose(fp2);

2.當(dāng)程序讀/寫數(shù)據(jù)文件時,需要有聲明語句“FILE*fp;”,在該聲明語句之前必須包含頭文件_______

溫馨提示

  • 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

提交評論