版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡介
第9章文件9.1文件概述9.2文件指針9.4文件的讀/寫9.5文件的定位9.6文件檢測函數(shù)
文件是計(jì)算機(jī)中經(jīng)常使用的一個(gè)重要概念。本章在敘述文件概念的基礎(chǔ)上,介紹文
件的基本操作和應(yīng)用,講解文件操作的基本過程,使讀者熟悉C語言中有關(guān)文件處理的庫函數(shù)。
學(xué)習(xí)重點(diǎn):
文件指針
文件的讀寫
9.1.1文件的定義
文件是指存儲(chǔ)在外部介質(zhì)(如磁盤和磁帶等外存儲(chǔ)器)上的數(shù)據(jù)或信息的集合。例如:源程序文件中保存著源程序,文本文件中保存著文本數(shù)據(jù),聲音文件中保存著聲音數(shù)據(jù)等。
為標(biāo)識(shí)一個(gè)文件,每個(gè)文件都必須有一個(gè)文件名,其一般結(jié)構(gòu)為:
主文件名[.擴(kuò)展名]9.1文件概述文件命名規(guī)則遵循操作系統(tǒng)的約定。計(jì)算機(jī)通過文件名對文件進(jìn)行讀、寫、修改和刪除等操作。
C語言實(shí)現(xiàn)文件操作的途徑主要有兩種:一是通過操作系統(tǒng)。由于操作系統(tǒng)是以文件為單位對數(shù)據(jù)進(jìn)行管理的,因此可以直接引用操作系統(tǒng)的系統(tǒng)調(diào)用,這屬于低級的操作,使用方法相對復(fù)雜,在現(xiàn)在的程序設(shè)計(jì)中已經(jīng)很少使用;二是通過由C語言編譯系統(tǒng)提供的一套用于文件操作的庫函數(shù),也稱為“標(biāo)準(zhǔn)輸入/輸出庫”。本章介紹通過標(biāo)準(zhǔn)輸入/輸出庫來使用文件。9.1.2文件的分類
可以從不同的角度對C語言的文件進(jìn)行分類:
(1)從用戶的角度看,文件可分為普通文件和設(shè)備文件。
普通文件是指駐留在磁盤或其他外部介質(zhì)上的數(shù)據(jù)集合,可以是源文件、目標(biāo)文件、可執(zhí)行程序,也可以是一組待輸入處理的原始數(shù)據(jù)或一組輸出的結(jié)果。
設(shè)備文件是指與主機(jī)相連的各種外部設(shè)備,如顯示器、打印機(jī)、鍵盤等。在操作系統(tǒng)中,外部設(shè)備也被看做是一個(gè)文件,并對其進(jìn)行管理,將它們的輸入、輸出等同于對磁盤文件的讀和寫。通常把顯示器定義為標(biāo)準(zhǔn)輸出文件,一般情況下在屏幕上顯示有關(guān)信息就是向標(biāo)準(zhǔn)輸出文件輸出。如前面經(jīng)常使用的printf、putchar函數(shù)就是這類輸出。
鍵盤通常被指定為標(biāo)準(zhǔn)的輸入文件,從鍵盤上輸入就意味著從標(biāo)準(zhǔn)輸入文件上輸入數(shù)據(jù)。scanf、getchar函數(shù)就屬于這類輸入。
(2)從數(shù)據(jù)組織形式的角度來看,文件可分為ASCII文件和二進(jìn)制文件。數(shù)據(jù)的組織形式是指數(shù)據(jù)在磁盤上的存儲(chǔ)形式。
ASCII文件又稱文本(TEXT)文件,它的數(shù)據(jù)是采用ASCII碼形式存儲(chǔ)的。每一個(gè)字節(jié)放一個(gè)ASCII代碼,代表一個(gè)字符。這樣的好處是便于對字符進(jìn)行逐個(gè)處理,也便于輸出字符。劣勢是占存儲(chǔ)空間較多,而且要花費(fèi)轉(zhuǎn)換時(shí)間(二進(jìn)制形式與ASCII碼間的轉(zhuǎn)換)。
二進(jìn)制文件與ASCII文件不同,它是把內(nèi)存中的數(shù)據(jù)按其在內(nèi)存中的存儲(chǔ)形式原樣輸出到磁盤上存放。這樣可以節(jié)省外存空間和轉(zhuǎn)換時(shí)間,但一個(gè)字節(jié)并不對應(yīng)一個(gè)字符,不能直接輸出字符形式。圖9-1int型十進(jìn)制數(shù)1024的存儲(chǔ)形式例如:int型的十進(jìn)制數(shù)1024用ASCII形式輸出要占用4個(gè)字節(jié);若按二進(jìn)制形式輸出則只占用2個(gè)字節(jié)。如圖9-1所示。
(3)從C語言對文件處理方法的角度來看,可以將文件分為緩沖文件系統(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ū)(給程序變量),如圖9-2所示。緩沖區(qū)的大小由各個(gè)具體的C語言版本確定,一般為512字節(jié)。
圖9-2文件的寫入—寫出所謂“非緩沖文件系統(tǒng)”,是指系統(tǒng)不自動(dòng)開辟確定大小的緩沖區(qū),而由程序?yàn)槊總€(gè)文件設(shè)定緩沖區(qū)。
用緩沖文件系統(tǒng)進(jìn)行的輸入/輸出又稱為高級磁盤輸入/輸出,用非緩沖進(jìn)行的輸入/輸出又稱為低級輸入/輸出系統(tǒng)。ANSIC標(biāo)準(zhǔn)不采用非緩沖文件系統(tǒng),而只采用緩沖文件系統(tǒng)。也就是說,既用緩沖文件系統(tǒng)處理文本文件,也用它來處理二進(jìn)制文件。
本章只介紹ANSIC標(biāo)準(zhǔn)中的緩沖文件系統(tǒng)及其相關(guān)的庫函數(shù)。
在緩沖文件系統(tǒng)中,涉及到的關(guān)鍵概念是“文件指針”。
對每個(gè)正在使用的文件都要定義一個(gè)FILE結(jié)構(gòu)體類型變量,該變量用于存放文件的有關(guān)信息,如文件名、文件狀態(tài)等。9.2文件指針
FILE結(jié)構(gòu)體類型不需要用戶自己定義,它是由系統(tǒng)事先定義的,固定包含在頭文件stdio.h中。其類型定義如下:
typedef
struct
{
short level; /*緩沖區(qū)“滿”或“空”的程度*/
unsigned flags; /*文件狀態(tài)標(biāo)志*/
char fd; /*文件描述符*/
unsignedchar hold; /*如無緩沖區(qū)不讀取字符*/
short bsize; /*緩沖區(qū)的大小*/
unsignedchar *buffer; /*數(shù)據(jù)緩沖區(qū)的位置*/
unsignedchar *curp; /*當(dāng)前讀寫位置*/
unsigned istemp; /*臨時(shí)文件,指示器*/
short token; /*用于有效性檢查*/
}FILE;
FILE是該結(jié)構(gòu)體類型的類型名。在C程序中,凡是要對已打開的文件進(jìn)行操作,都要通過指向該文件的FILE結(jié)構(gòu)體變量的指針。為此,需要在程序中定義一個(gè)FILE型(文件型)指針變量。
文件型指針變量定義的形式為:
FILE*文件型指針名;
例如:
FILE*fp;
fp定義為一個(gè)FILE結(jié)構(gòu)體類型的指針變量。通過fp可尋找存放某個(gè)文件信息的結(jié)構(gòu)體變量,然后按結(jié)構(gòu)體變量提供的信息找到該文件,從而實(shí)施對文件的操作。習(xí)慣上也籠統(tǒng)地把fp稱為指向一個(gè)文件的指針。
文件在進(jìn)行讀/寫操作之前要先打開,使用完畢要關(guān)閉。所謂打開文件,實(shí)際上是建立文件的各種有關(guān)信息,并使文件指針指向該文件,以便進(jìn)行其他操作。關(guān)閉文件則斷開指針與文件之間的聯(lián)系,也就禁止再對該文件進(jìn)行操作。
在C語言中,文件操作都是由庫函數(shù)來完成的。9.3文件的打開與關(guān)閉9.3.1文件打開函數(shù)(fopen)
fopen函數(shù)用來打開一個(gè)文件,其調(diào)用的一般形式為:
文件指針名=fopen(文件名,使用文件方式);
其中,“文件名”是被打開文件的文件名,它是字符串常量或字符串?dāng)?shù)組;“使用文件方式”是指文件的類型和操作要求;“文件指針名”是一個(gè)FILE類型的指針變量,它保存fopen函數(shù)返回指向被打開文件的指針。例如:
FILE*fp;
fp=("file1","r");
其功能是在當(dāng)前目錄下打開文件file1,只允許進(jìn)行“讀”操作,并使fp指向該文件。
又如:
FILE*fp;
fp=("c:\\a.dat","rb");其功能是打開C盤根目錄下的文件a.dat,這是一個(gè)二進(jìn)制文件,只允許按二進(jìn)制方式進(jìn)行讀操作。
文件使用方式共有12種,表9-1給出了它們的符號和含義。表9-1文件使用方式的符號和含義對于使用文件方式有以下幾點(diǎn)說明:
(1)使用文件方式由“r”、“w”、“a”、“b”和“+”五個(gè)字符組成,各字符的含義分
別是:
r(read) 讀
w(write) 寫
a(append) 追加
b(banary) 二進(jìn)制文件
+ 讀和寫
(2)凡用“r”打開一個(gè)文件時(shí),該文件必須已經(jīng)存在,且只能從該文件讀出。
(3)用“w”打開的文件只能向該文件寫入。若打開的文件不存在,則以指定的文件名建立該文件,若打開的文件已經(jīng)存在,則將該文件刪去,重建一個(gè)新文件。
(4)若要向一個(gè)已存在的文件追加新的信息,只能用“a”方式打開文件。
(5)用“r+”、“w+”、“a+”方式打開的文件可以用來輸入和輸出數(shù)據(jù)。用“r+”方式時(shí)該文件應(yīng)該已經(jīng)存在,以便能向計(jì)算機(jī)輸入數(shù)據(jù)。用“w+”方式則新建立一個(gè)文件,先向此文件寫數(shù)據(jù),然后可以讀此文件中的數(shù)據(jù)。用“a+”方式打開的文件,原來的文件不被刪去,位置指針移到文件末尾,則可以添加,也可以讀。
(6)在打開一個(gè)文件時(shí),如果出錯(cuò),fopen將返回一個(gè)空指針值NULL。在程序中可以用這一信息來判別是否完成打開文件的工作,并作相應(yīng)的處理。因此常用下面的方法打開一個(gè)文件:
if((fp=fopen("file1","r")==NULL)
{
printf("Cannotopenfile1!\n");
exit(0);
}
這段程序的意義是:如果fopen返回的指針為空,則表示不能打開文件file1,并給出提示信息“Cannotopenfile1!”,然后執(zhí)行exit(0)退出程序。如果fopen返回的指針不為空,則繼續(xù)執(zhí)行“{}”后面的語句。
(7)把一個(gè)文本文件讀入內(nèi)存時(shí),要將ASCII碼轉(zhuǎn)換成二進(jìn)制碼;而把文件以文本方式寫入磁盤時(shí),也要把二進(jìn)制碼轉(zhuǎn)換成ASCII碼。因此,對文本文件的讀/寫要花費(fèi)較多的轉(zhuǎn)換時(shí)間,對二進(jìn)制文件的讀/寫則不存在這種轉(zhuǎn)換。
(8)在程序開始運(yùn)行時(shí),系統(tǒng)自動(dòng)打開三個(gè)標(biāo)準(zhǔn)文件,即標(biāo)準(zhǔn)輸入、標(biāo)準(zhǔn)輸出、標(biāo)準(zhǔn)出錯(cuò)輸出,并分別用文件指針stdin、stdout、stderr指向它們。9.3.2文件關(guān)閉函數(shù)(fclose)
文件一旦使用完畢,應(yīng)用文件關(guān)閉函數(shù)把文件關(guān)閉。文件關(guān)閉后,文件指針變量不再指向該文件,此后不能再通過該指針對該文件進(jìn)行讀/寫操作,除非再次打開,使該指針變量重新指向該文件。
fclose函數(shù)調(diào)用的一般形式為:
fclose(文件指針);
例如:
fclose(fp);
正常完成關(guān)閉文件操作時(shí),fclose函數(shù)返回值為0。如返回非零值則表示有錯(cuò)誤發(fā)生。在程序終止之前必須關(guān)閉所有使用的文件。如果不關(guān)閉,可能會(huì)造成數(shù)據(jù)丟失。因?yàn)樵谙蛭募憯?shù)據(jù)時(shí),先將數(shù)據(jù)輸?shù)骄彌_區(qū),待緩沖區(qū)充滿后才寫到磁盤上的文件中。如果當(dāng)數(shù)據(jù)未充滿緩沖區(qū)而程序結(jié)束運(yùn)行,就會(huì)將緩沖區(qū)中的數(shù)據(jù)丟失。而用fclose函數(shù)關(guān)閉文件,將把緩沖區(qū)中的數(shù)據(jù)寫到磁盤文件,然后釋放文件指針變量。
文件打開之后,就可以對它進(jìn)行讀/寫了。C語言編譯系統(tǒng)提供了多種文件讀/寫的函數(shù),它們都包含在頭文件stdio.h中。9.4文件的讀/寫9.4.1字符讀/寫函數(shù)fgetc和fputc
1.讀字符函數(shù)fgetc()
fgetc函數(shù)的功能是從指定的文件中讀取一個(gè)字符,其調(diào)用形式為:
ch=fgetc(fp);
其中,fp為文件型指針變量,ch為字符變量。fgetc函數(shù)返回讀取的字符,并把它賦給ch。若讀取字符時(shí)文件已經(jīng)結(jié)束,則函數(shù)返回文件結(jié)束標(biāo)記EOF。EOF是在頭文件stdio.h中定義的符號常量,其值為
-1。例如,要從磁盤文件中順序讀入字符并在屏幕上顯示,可通過調(diào)用fgetc函數(shù)實(shí)現(xiàn):
while((c=fgetc(fp))!=EOF)
putchar(c);
注意:文件結(jié)束標(biāo)記EOF是不可輸出字符,不能在屏幕上顯示。由于字符的ASCII碼不可能出現(xiàn)
-1,因此EOF定義為
-1是合適的。
對于fgetc函數(shù)的使用有以下幾點(diǎn)說明:
(1)在fgetc函數(shù)調(diào)用中,讀取的文件必須是以讀或讀寫方式打開的。
(2)讀取字符的結(jié)果也可以不向字符變量賦值,
例如:
fgetc(fp);
但是讀出的字符不能保存。
(3)在文件內(nèi)部有一個(gè)位置指針,用來指向文件的當(dāng)前讀寫字節(jié)。在文件打開時(shí),該指針總是指向文件的第一個(gè)字節(jié)。使用fgetc
函數(shù)后,該位置指針將向后移動(dòng)一個(gè)字節(jié),因此可連續(xù)多次使用fgetc函數(shù)來讀取多個(gè)字符。
應(yīng)注意:文件指針和文件內(nèi)部的位置指針不是一回事。文件指針是指向整個(gè)文件的,須在程序中定義說明,只要不重新賦值,文件指針的值是不變的。文件內(nèi)部的位置指針用以指示文件內(nèi)部的當(dāng)前讀寫位置,每讀寫一次,該指針均向后移動(dòng),它不需在程序中定義說明,而是由系統(tǒng)自動(dòng)設(shè)置的。
(4)現(xiàn)在ANSIC已允許用緩沖文件系統(tǒng)處理二進(jìn)制文件,而讀入某一個(gè)字節(jié)中的二進(jìn)制數(shù)據(jù)的值有可能是-1,而這又恰好是EOF的值,這就出現(xiàn)了讀入的有用數(shù)據(jù)卻被處理為“文件結(jié)束”的情況。為了解決這個(gè)問題,ANSIC提供一個(gè)feof函數(shù)來判斷文件是否真的結(jié)束。feof(fp)用來測試fp所指向的文件當(dāng)前狀態(tài)是否“文件結(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(可以接著對這些數(shù)據(jù)進(jìn)行處理)。直到遇文件結(jié)束,feof(fp)的值為1,!feof(fp)的值為0,也就不再執(zhí)行while循環(huán)。
這種方法也適用于文本文件。
【例9-1】在屏幕上顯示文本文件的內(nèi)容。
#include<stdio.h>
#indude<process.h>
voidmain()
{
FILE*fp;
charfilename[20],ch;
printf("Pleaeinputfilename:");
scanf("%s",filename); /*輸入文件名*/
if((fp=fopen(filename,"r"))==NULL) /*打開文件*/
{
printf("Cannotopen%s!\n",filename); /*出錯(cuò)處理*/
exit(0);
}
while((ch=fgetc(fp))!=EOF) /*從文件中讀字符*/
putchar(ch); /*顯示從文件讀入的字符*/
fclose(fp); /*關(guān)閉文件*/
}程序運(yùn)行時(shí),先提示輸入文件名(需包含路徑,否則該文件應(yīng)該在程序根目錄下),然后程序以只讀方式打開該文件。如果正確打開文件,則讀出每個(gè)字符,并顯示在屏幕上,然后關(guān)閉文件;如果打開文件時(shí)出錯(cuò),則顯示不能打開文件的信息,然后退出程序。
2.寫字符函數(shù)fputc()
fputc函數(shù)的功能是將一個(gè)字符輸出到指定文件中,其調(diào)用形式為:
fputc(ch,fp);
其中,ch是要輸出的字符(可為字符常量或字符變量),fp為文件型指針變量。函數(shù)將字符(ch的值)輸出到fp所指向的文件中。如果輸出成功,則返回值就是輸出的字符;如果輸出失敗,則返回EOF。
前面介紹過的putchar函數(shù)其實(shí)就是從fputc函數(shù)派生出來的。putchar(c)是用#define定義的宏:
#defineputchar(c)fputc(c,stdout)其中,stdout是系統(tǒng)定義的文件指針變量,它指向終端輸出;fputc(c,stdout)的作用是將c的值輸出到終端。用宏putchar(c)比寫fputc(c,stdout)簡單一些,從用戶的角度,可以把putchar(c)看做函數(shù)而不必嚴(yán)格地稱它為宏。
對于fputc函數(shù)的使用有以下幾點(diǎn)說明:
(1)被寫入的文件可以用寫、讀寫、追加方式打開。用寫或讀寫方式打開一個(gè)已存在的文件時(shí),將清除原有的文件內(nèi)容。寫入字符從文件首開始。如需保留原有文件內(nèi)容,希望把寫入的字符存放到文件末,必須以追加方式打開文件。被寫入的文件若不存在,則創(chuàng)建該文件。
(2)每寫入一個(gè)字符,文件內(nèi)部位置指針向后移動(dòng)一個(gè)字節(jié)。
【例9-2】編程完成文本文件的復(fù)制。
#include<stdio.h>
voidmain()
{
FILE*fp1,*fp2;
charfile1[20],file2[20],ch;
printf("Pleaseinputfilename1:");
scanf("%s",file1);
printf("Pleaseinputfilename2:");
scanf("%s",file2);
if((fp1=fopen(file1,"r"))==NULL)/*以“只讀”方式打開文件1*/
{
printf("Cannotopen%s!\n",file1);
exit(0);
}
if((fp2=fopen(file2,"w"))==NULL) /*以“寫”方式打開文件2*/
{
printf("Cannotopen%s!\n",file2);
exit(0);
}
while((ch=fgetc(fp1))!=EOF) /*從文件fp1中讀字符*/
fputc(ch,fp2); /*寫入文件fp2中*/
fclose(fp1); /*關(guān)閉兩個(gè)文件*/
fclose(fp2);
}
程序運(yùn)行結(jié)果為:
Pleaseinputfilename1:e:\test.txt<回車>
Pleaseinputfilename2:e:\test1.txt<回車>
test.txt為原有文件,在E盤根目錄下;test1.txt為新復(fù)制的文件,也在E盤根目錄下。
也可以在輸入命令行時(shí)把兩個(gè)文件名一起輸入。這時(shí)要用到main函數(shù)的參數(shù)。程序可改為:
#include<stdio.h>
voidmain(int
argc,char*argv[])
{
FILE*fp1,*fp2;
charch;
if(argc!=3)
{
printf("Mustinputtwofilenames!\n");
exit(0);
}
if((fp1=fopen(argv[1],"r"))==NULL)/*以“只讀”方式打開文件1*/
{
printf("Cannotopen%s!\n",argv[1]);
exit(0);
}
if((fp2=fopen(argv[2],"w"))==NULL)/*以“寫”方式打開文件2*/
{
printf("Cannotopen%s!\n",argv[2]);
exit(0);
}
while((ch=fgetc(fp1))!=EOF) /*從文件fp1中讀字符*/
fputc(ch,fp2); /*寫入文件fp2中*/
fclose(fp1); /*關(guān)閉兩個(gè)文件*/
fclose(fp2);
}假設(shè)該程序的源文件名為MyCopy.c,經(jīng)編譯、連接后得到的可執(zhí)行文件名為
MyCopy.exe,
把它放在C盤根目錄下,
則在DOS命令提示符窗口中,
可按如下方式復(fù)制
文件:
C:\>MyCopy
e:\test.txte:\test1.txt<回車>9.4.2字符串讀/寫函數(shù)fgets和fputs
fgets()和fputs()函數(shù)是以字符串為單位對文件進(jìn)行讀/寫的,由于這兩個(gè)函數(shù)在使用中往往是一次讀/寫一行,所以也稱為行讀/寫函數(shù)。
1.讀字符串函數(shù)fgets()
fgets函數(shù)的功能是從指定的文件中讀一個(gè)字符串到字符數(shù)組中,其調(diào)用形式為:
fgets(字符數(shù)組名,n,文件指針);
其中,n是一個(gè)正整數(shù),表示從文件中讀出n-1個(gè)字符,并在最后一個(gè)字符后加上串結(jié)束標(biāo)志
'\0',將它們一起放入字符數(shù)組中。如果在讀入n-1個(gè)字符結(jié)束之前遇到換行符或EOF,讀入即結(jié)束。如果操作正確,函數(shù)的返回值為字符數(shù)組的首地址;如果文件結(jié)束或出錯(cuò),則函數(shù)的返回值為NULL。
【例9-3】從D盤根目錄下的test.txt文件中讀入一個(gè)含10個(gè)字符的字符串。
#include<stdio.h>
voidmain()
{
FILE*fp;
charstr[11];
if((fp=fopen("d:\\test.txt","r"))==NULL)
{
printf("Cannotopenfile!");
exit(0);
}
fgets(str,11,fp);
printf("\n%s\n",str);
fclose(fp);
}本例定義了一個(gè)字符數(shù)組str共11個(gè)字節(jié),在以只讀文件方式打開D盤上文件test.txt后,從中讀出10個(gè)字符送入str數(shù)組,在數(shù)組最后一個(gè)單元內(nèi)將加上
'\0',然后在屏幕上顯示輸出str數(shù)組。
2.寫字符串函數(shù)fputs()
fputs函數(shù)的功能是向指定的文件寫入一個(gè)字符串,其調(diào)用形式為:
fputs(字符串,文件指針);
其中,“字符串”可以是字符串常量,也可以是字符數(shù)組名或字符型指針變量,例如:
fputs("abcd",fp);
其意義是把字符串
"abcd"
寫入fp所指的文件之中。
【例9-4】從鍵盤輸入若干行字符存入D盤根目錄下的文件file.txt中。
#include<stdio.h>
#include<string.h>
voidmain()
{
FILE*fp;
charstr[81];
if((fp=fopen("D:\\file.txt","w"))==NULL)
{
printf("Cannotopenfile!\n");
exit(0);
}
while(strlen(gets(str))>0)
{
fputs(str,fp);fputs("\n",fp);
}
fclose(fp);
}程序以只寫方式打開D盤根目錄下的文件file.txt后,用一個(gè)while循環(huán)來完成從鍵盤輸入字符串,并把字符串寫到文件中。gets(str)表示從鍵盤獲取字符串,并把它保存到字符數(shù)組str中。strlen()函數(shù)測試輸入的字符串的字符個(gè)數(shù),如果大于0,則用函數(shù)fputs把保存在str中的字符串寫到文件中。fputs("\n",fp)表示向文件中輸入一個(gè)換行符,使位置指針移到下一行開始。9.4.3數(shù)據(jù)塊讀/寫函數(shù)fread和fwrite
C語言提供了讀寫整塊數(shù)據(jù)的函數(shù)fread和fwrite。它們可用來讀/寫一組數(shù)據(jù),如一個(gè)數(shù)組元素,一個(gè)結(jié)構(gòu)體變量的值等。
讀數(shù)據(jù)塊函數(shù)調(diào)用的一般形式為:
fread(buffer,size,count,fp);
寫數(shù)據(jù)塊函數(shù)調(diào)用的一般形式為:
fwrite(buffer,size,count,fp);
其中:buffer是一個(gè)指針。在fread函數(shù)中,它表示存放輸入數(shù)據(jù)的首地址;在fwrite函數(shù)中,它表示存放輸出數(shù)據(jù)的首地址。size表示數(shù)據(jù)塊的字節(jié)數(shù)。count表示要讀/寫的數(shù)據(jù)塊塊數(shù)。fp表示文件指針。
例如:
fread(fa,4,5,fp);
其意義是從fp所指的文件中,每次讀4個(gè)字節(jié)(一個(gè)實(shí)數(shù))送入實(shí)數(shù)數(shù)組fa中,連續(xù)讀5次,即讀5個(gè)實(shí)數(shù)到fa中。
【例9-5】定義一個(gè)包含學(xué)生信息的結(jié)構(gòu)體變量,其中包括學(xué)號、姓名、年齡、班級等幾個(gè)成員。然后從鍵盤輸入3個(gè)學(xué)生的信息,并把它們存儲(chǔ)到D盤根目錄下的文件student.dat中。
源程序如下:
#include<stdio.h>
structstudent
{
intnumber;
charname[10];
intage;
charclass[10];
};
voidmain()
{
FILE*fp;
structstudents;
inti,size;
size=sizeof(structstudent);
if((fp=fopen("D:\\student.dat","wb"))==NULL)
{
printf("Cannotopenthefile!");
exit(0);
}
for(i=0;i<3;i++)
{
scanf("%d%s%d%s",&s.number,&,&s.age,&s.class);
fwrite(&s,size,1,fp);
}
fclose(fp);
}程序運(yùn)行結(jié)果為:
101wang20200203<回車>
102zeng19200203<回車>
103zhang19200203<回車>
該程序定義了一個(gè)結(jié)構(gòu)體類型student。先打開或建立D盤上的二進(jìn)制文件student.dat,然后用一個(gè)for循環(huán)依次輸入3個(gè)學(xué)生的學(xué)號、姓名、年齡和班級。每輸入一個(gè)學(xué)生的信息,就把它寫入文件。sizeof(structstudent)是求結(jié)構(gòu)體類型student的長度(字節(jié)數(shù))。fwrite(&s,size,1,fp)是把結(jié)構(gòu)體變量的內(nèi)容寫入fp所指的文件中,注意必須傳遞變量s的地址給函數(shù),“1”表示輸出1個(gè)結(jié)構(gòu)體變量的內(nèi)容。
【例9-6】D盤根目錄下的文件student.dat中存儲(chǔ)有學(xué)生的學(xué)號、姓名、年齡、班級等信息,編寫程序把年齡小于20歲的學(xué)生信息顯示出來。
源程序如下:
#include<stdio.h>
structstudent
{
intnumber;
charname[10];
intage;
charclass[10];
};
voidmain()
{
FILE*fp;
structstudents;
intsize;
size=sizeof(structstudent);
if((fp=fopen("D:\\student.dat","rb"))==NULL)
{
printf("Cannotopenthefile!");
exit(0);
}
while(!feof(fp))
{
fread(&s,size,1,fp);
if(s.age<20)
printf("%d%s%d%s\n",s.number,,s.age,s.class);
}
fclose(fp);
}
程序運(yùn)行結(jié)果為:
102zeng19200203
103zhang192002039.4.4格式化讀/寫函數(shù)fscanf和fprintf
函數(shù)fscanf和fprintf與前面使用的scanf和printf功能相似,都是格式化讀/寫函數(shù)。兩者的區(qū)別在于:fscanf和fprintf的讀/寫對象是磁盤文件;scanf和printf的讀/寫對象是標(biāo)準(zhǔn)輸入/輸出設(shè)備(鍵盤/顯示器)。
fscanf函數(shù)和fprintf函數(shù)的調(diào)用形式分別為:
fscanf(文件指針,格式字符串,輸入表列);
fprintf(文件指針,格式字符串,輸出表列);
例如:
fscanf(fp,"%d%s",&i,s);該語句是從fp所指的文件中讀入一個(gè)整數(shù)和一個(gè)字符串,分別送給整型變量i和字符數(shù)組s。
又如:
fprintf(fp,"%d%c",j,ch);
該語句把整型變量j和字符變量ch的值依次寫入fp所指的文件中。
可以看到,函數(shù)fscanf和fprintf與函數(shù)scanf和printf的格式也非常類似,只是多了文件指針項(xiàng),用于指明要操作的文件,而格式字符串和輸入/輸出表列與scanf和printf中的規(guī)則完全一致。【例9-7】從鍵盤輸入一個(gè)字符串和一個(gè)十進(jìn)制整數(shù),并將它們寫入test.txt文件中,然后再從test.txt文件中讀出并顯示在屏幕上。
源程序如下:
#include<stdio.h>
voidmain()
{
chars[81];
inta;
FILE*fp;
if((fp=fopen("test.txt","w"))==NULL) /*以寫方式打開文本文件*/
{
printf("Cannotopenfile.\n");
exit(0);
}
printf("Pleaseinputastringandainteger:\n");
fscanf(stdin,"%s%d",s,&a); /*從標(biāo)準(zhǔn)輸入設(shè)備(鍵盤)上讀取數(shù)據(jù)*/
fprintf(fp,"%s%d",s,a); /*以格式輸出方式寫入文件*/
fclose(fp); /*寫文件結(jié)束關(guān)閉文件*/
printf("Begoingtoprintastringandaintegerfromthefiletest.txt!\n");
if((fp=fopen("test.txt","r"))==NULL) /*以讀方式打開文本文件*/
{
printf("Cannotopenfile.\n");
exit(0);
}
fscanf(fp,"%s%d",s,&a); /*以格式輸入方式從文件讀取數(shù)據(jù)*/
fprintf(stdout,"%s%d\n",s,a); /*將數(shù)據(jù)顯示到標(biāo)準(zhǔn)輸出設(shè)備(屏幕)上*/
fclose(fp); /*讀文件結(jié)束關(guān)閉文件*/
}
程序運(yùn)行結(jié)果為:
Pleaseinputastringandainteger:
abce12359<回車>
Begoingtoprintastringandaintegerfromthefiletest.txt!
abce12359
該程序在從鍵盤輸入數(shù)據(jù)時(shí)使用fscanf(stdin,"%s%d",s,&a),它同scanf("%s%d",s,&a)的功能相同。同樣,fprintf(stdout,"%s%d\n",s,a)與printf("%s%d\n",s,a)的功能也相同。
前面提到,文件中有一個(gè)位置指針,指向當(dāng)前讀/寫的位置。文件剛打開時(shí),位置指針指向開始位置或者末尾。利用前面介紹的函數(shù)讀/寫后,位置指針則會(huì)往后移動(dòng)相應(yīng)長度的距離。也就是說,文件的讀/寫是順序往后進(jìn)行的,但在實(shí)際問題中有時(shí)需要只讀/寫文件中某一指定的部分。為此,C語言編譯系統(tǒng)提供了移動(dòng)文件位置指針的函數(shù)。9.5文?件?的?定?位9.5.1fseek函數(shù)
fseek函數(shù)用來移動(dòng)文件的位置指針,其調(diào)用形式為:
fseek(文件指針,位移量,起始點(diǎn));
其中:“文件指針”指向文件?!拔灰屏俊北硎疽苿?dòng)的字節(jié)數(shù),要求位移量是long型數(shù)據(jù),以便在文件長度大于64
KB時(shí)不會(huì)出錯(cuò)。當(dāng)用常量表示位移量時(shí),要求加后綴“L”?!捌鹗键c(diǎn)”表示從何處開始計(jì)算位移量,規(guī)定的起始點(diǎn)有三種:文件首,當(dāng)前位置和文件尾。其表示方法如表9-2所示。表9-2起始點(diǎn)的表示例如:
fseek(fp,100L,0);
其意義是把fp所指文件的位置指針移到離文件首100個(gè)字節(jié)處。
又如:
fseek(fp,
-10L,2);
其意義是將位置指針從文件末尾處向后退(即往文件開始方向)10個(gè)字節(jié)。
應(yīng)該注意的是:fseek函數(shù)一般用于二進(jìn)制文件,因?yàn)槲谋疚募l(fā)生字符轉(zhuǎn)換,計(jì)算位置時(shí)往往會(huì)發(fā)生混亂。
【例9-8】例9-5中,在D盤根目錄下的文件student.dat中存儲(chǔ)了3個(gè)學(xué)生的學(xué)號、姓名、年齡、班級等信息,編寫程序把第2個(gè)學(xué)生信息顯示出來。
源程序如下:
#include<stdio.h>
structstudent
{
intnumber;
charname[10];
intage;
charclass[10];
};
voidmain()
{
FILE*fp;
structstudents;
inti,size;
size=sizeof(structstudent);
if((fp=fopen("D:\\student.dat","rb"))==NULL)
{
printf("Cannotopenthefile!");
exit(0);
}
fseek(fp,size,0);
fread(&s,size,1,fp);
printf("%d%s%d%s\n",s.number,,s.age,s.class);
fclose(fp);
}程序運(yùn)行結(jié)果為:
102zeng19200203
該程序中的fseek(fp,size,0)將文件的位置指針相對于文件開始向后移動(dòng)一個(gè)student結(jié)構(gòu)體的字節(jié)數(shù),即移到第2個(gè)學(xué)生信息的開始位置。9.5.2rewind函數(shù)
rewind函數(shù)的作用是使位置指針重新返回文件的開頭,其調(diào)用形式為:
rewind(文件指針);
例如:
rewind(fp);
其意義是將fp所指文件的位置指針重新移到文件開頭。
【例9-9
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(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ǔ)空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 上海工會(huì)管理職業(yè)學(xué)院《圖形與圖像處理》2023-2024學(xué)年第一學(xué)期期末試卷
- 網(wǎng)絡(luò)管理員技能鑒定測試題(附參考答案)
- 幼兒園冬至集體課程設(shè)計(jì)
- 聲樂培訓(xùn)行業(yè)發(fā)展趨勢報(bào)告
- 早教數(shù)理課特色課程設(shè)計(jì)
- 電氣工程師供配電練習(xí)
- 加強(qiáng)中小學(xué)科學(xué)實(shí)驗(yàn)教學(xué)的實(shí)效性
- 廣西xx工業(yè)廢鹽資源化利用項(xiàng)目可行性研究報(bào)告
- 平安夜圣誕節(jié)介紹活動(dòng)方案326
- 未來救護(hù)車課程設(shè)計(jì)
- 動(dòng)畫分鏡頭腳本文檔模板
- 配網(wǎng)規(guī)劃工作思路
- 項(xiàng)目復(fù)盤報(bào)告PPT通用模板
- 心理統(tǒng)計(jì)學(xué)考研歷年真題及答案
- 辦公樓室內(nèi)精裝修工程施工組織設(shè)計(jì)方案(同名74275)
- 2023年諸暨市提前招生選拔考試科學(xué)試卷
- 標(biāo)準(zhǔn)化預(yù)制梁場驗(yàn)收表
- GB/T 39604-2020社會(huì)責(zé)任管理體系要求及使用指南
- 幼兒園主題教育活動(dòng)設(shè)計(jì)與實(shí)施課件
- 實(shí)驗(yàn)室生物安全程序文件
- 一年級上冊數(shù)學(xué)解決問題50道【綜合題】
評論
0/150
提交評論