




版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
10文件現(xiàn)在我們接觸最多的都是短視頻,手機(jī)APP里面的短視頻都是制作者通過(guò)文件的形式上傳到服務(wù)器當(dāng)中的。又比如我們要打印個(gè)人簡(jiǎn)歷,需要先把制作好的個(gè)人簡(jiǎn)歷通過(guò)文件的形式保存在U盤(pán)里面去打印店打印。在我們?nèi)粘I钪惺墙?jīng)常需要接觸到文件的。在軟件開(kāi)發(fā)當(dāng)中也是如此,現(xiàn)在都是大數(shù)據(jù)時(shí)代,我們處理的數(shù)據(jù)都是海量的,不可能每次都手動(dòng)錄入、程序運(yùn)行完以后數(shù)據(jù)就丟失了。在程序中使用文件之前應(yīng)了解有關(guān)文件的基本知識(shí)。1.什么是文件文件有不同的類型,在程序設(shè)計(jì)中,主要用到兩種文件:(1)程序文件。包括源程序文件(后綴為.c)、目標(biāo)文件(后綴為.obj)、可執(zhí)行文件(后綴為.exe)等。這種文件的內(nèi)容是程序代碼。(2)數(shù)據(jù)文件。文件的內(nèi)容不是程序,而是供程序運(yùn)行時(shí)讀寫(xiě)的數(shù)據(jù),如在程序運(yùn)行過(guò)程中輸出到磁盤(pán)(或其他外部設(shè)備)的數(shù)據(jù),或在程序運(yùn)行過(guò)程中供讀人的數(shù)據(jù)。如一個(gè)年級(jí)學(xué)生的成績(jī)數(shù)據(jù)、貨物交易的數(shù)據(jù)等。本章主要討論的是數(shù)據(jù)文件。在以前各章中所處理的數(shù)據(jù)的輸入和輸出,都是以終端為對(duì)象的,即從終端的鍵盤(pán)輸入數(shù)據(jù),運(yùn)行結(jié)果輸出到終端顯示器上。實(shí)際上,常常需要將一些數(shù)據(jù)(運(yùn)行的最終結(jié)果或中間數(shù)據(jù))輸出到磁盤(pán)上保存起來(lái),以后需要時(shí)再?gòu)拇疟P(pán)中輸人到計(jì)算機(jī)內(nèi)存。這就要用到磁盤(pán)文件。10.1文件的相關(guān)概念1.什么是文件為了簡(jiǎn)化用戶對(duì)輸入輸出設(shè)備的操作,使用戶不必去區(qū)分各種輸入輸出設(shè)備之間的區(qū)別,操作系統(tǒng)把各種設(shè)備都統(tǒng)一作為文件來(lái)處理。從操作系統(tǒng)的角度看,每一個(gè)與主機(jī)相連的輸入輸出設(shè)備都看作一個(gè)文件。例如,終端鍵盤(pán)是輸入文件,顯示屏和打印機(jī)是輸出文件。文件(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ù)據(jù)。1.什么是文件輸入輸出是數(shù)據(jù)傳送的過(guò)程,數(shù)據(jù)如流水一樣從一處流向另一處,因此常將輸人輸出形象地稱為流(stream),即數(shù)據(jù)流。流表示了信息從源到目的端的流動(dòng)。在輸入操作時(shí),數(shù)據(jù)從文件流向計(jì)算機(jī)內(nèi)存,在輸出操作時(shí),數(shù)據(jù)從計(jì)算機(jī)流向文件(如打印機(jī)、磁盤(pán)文件)。文件是由操作系統(tǒng)進(jìn)行統(tǒng)一管理的,無(wú)論是用Word打開(kāi)或保存文件,還是C程序中的輸入輸出都是通過(guò)操作系統(tǒng)進(jìn)行的。“流”是一個(gè)傳輸通道,數(shù)據(jù)可以從運(yùn)行環(huán)境(有關(guān)設(shè)備)流入程序中,或從程序流至運(yùn)行環(huán)境。C語(yǔ)言把文件看作一個(gè)字符(或字節(jié))的序列,即由一個(gè)一個(gè)字符(或字節(jié))的數(shù)據(jù)順序組成。一個(gè)輸入輸出流就是一個(gè)字符流或字節(jié)(內(nèi)容為二進(jìn)制數(shù)據(jù))流。1.什么是文件C的數(shù)據(jù)文件由一連串的字符(或字節(jié))組成,而不考慮行的界限,兩行數(shù)據(jù)間不會(huì)自動(dòng)加分隔符,對(duì)文件的存取是以字符(字節(jié))為單位的。輸入輸出數(shù)據(jù)流的開(kāi)始和結(jié)束僅受程序控制而不受物理符號(hào)(如回車換行符)控制,這就增加了處理的靈活性。這種文件稱為流式文件。2.文件名2.文件名一個(gè)文件要有一個(gè)唯一的文件標(biāo)識(shí),以便用戶識(shí)別和引用。文件標(biāo)識(shí)包括3部分:(1)文件路徑(2)文件名主干(3)文件后綴文件路徑表示文件在外部存儲(chǔ)設(shè)備中的位置。如:圖10-1文件路徑2.文件名表示file1.da文件存放在C盤(pán)中的Users目錄下的GZY子目錄下的Downloads子目錄下面。為方便起見(jiàn),文件標(biāo)識(shí)常被稱為文件名,但應(yīng)了解此時(shí)所稱的文件名,實(shí)際上包括以上3部分內(nèi)容,而不僅是文件名主干。文件名主干的命名規(guī)則遵循標(biāo)識(shí)符的命名規(guī)則。后綴用來(lái)表示文件的性質(zhì),如:docx(Word生成的文件),txt(文本文件),dat(數(shù)據(jù)文件),c(C語(yǔ)言源程序文件),cpp(C++源程序文件),java(JAVA語(yǔ)言源程序文件),py(Python語(yǔ)言源程序文件),obj(目標(biāo)文件),exe(可執(zhí)行文件),pptx(電子幻燈文件),bmp(圖形文件)等。3.文件的分類3.文件的分類根據(jù)數(shù)據(jù)的組織形式,數(shù)據(jù)文件可分為ASCII文件和二進(jìn)制文件。數(shù)據(jù)在內(nèi)存中是以二進(jìn)制形式存儲(chǔ)的,如果不加轉(zhuǎn)換地輸出到外存,就是二進(jìn)制文件,可以認(rèn)為它就是存儲(chǔ)在內(nèi)存的數(shù)據(jù)的映像,所以也稱之為映像文件(imagefile)。如果要求在外存上以ASCII代碼形式存儲(chǔ),則需要在存儲(chǔ)前進(jìn)行轉(zhuǎn)換。ASCII文件又稱文本文件(textfile),每一個(gè)字節(jié)存放一個(gè)字符的ASCII代碼。一個(gè)數(shù)據(jù)在磁盤(pán)上怎樣存儲(chǔ)呢?字符一律以ASCII形式存儲(chǔ),數(shù)值型數(shù)據(jù)既可以用ASCII形式存儲(chǔ),也可以用二進(jìn)制形式存儲(chǔ)。如有整數(shù)202,0,如果用ASCII碼形式輸出到磁盤(pán),則在磁盤(pán)中占5個(gè)字節(jié)(每一個(gè)字符占一個(gè)字節(jié)),而用二進(jìn)制形式輸出,則在磁盤(pán)上只占4個(gè)字節(jié)。3.文件的分類用ASCII碼形式輸出時(shí)字節(jié)與字符一一對(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í)間,把內(nèi)存中的存儲(chǔ)單元中的內(nèi)容原封不動(dòng)地輸出到磁盤(pán)(或其他外部介質(zhì))上,此時(shí)每一個(gè)字節(jié)并不一定代表一個(gè)字符。如果程序運(yùn)行過(guò)程中有的中間數(shù)據(jù)需要保存在外部介質(zhì)上,以便在需要時(shí)再輸入到內(nèi)存,一般用二進(jìn)制文件比較方便。在事務(wù)管理中,常有大批數(shù)據(jù)存放在磁盤(pán)上,隨時(shí)調(diào)入計(jì)算機(jī)進(jìn)行查詢或處理,然后又把修改過(guò)的信息再存回磁盤(pán),這時(shí)也常用二進(jìn)制文件。4.文件緩沖區(qū)4.文件的緩沖區(qū)ANSIC標(biāo)準(zhǔn)采用“緩沖文件系統(tǒng)”處理數(shù)據(jù)文件,所謂緩沖文件系統(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)向計(jì)算機(jī)讀入數(shù)據(jù),則一次從磁盤(pán)文件將一批數(shù)據(jù)輸入到內(nèi)存緩沖區(qū)(充滿緩沖區(qū)),然后再?gòu)木彌_區(qū)逐個(gè)地將數(shù)據(jù)送到程序數(shù)據(jù)區(qū)(給程序變量)。這樣做是為了節(jié)省存取時(shí)間,提高效率,緩沖區(qū)的大小由各個(gè)具體的C編譯系統(tǒng)確定?!菊f(shuō)明】每一個(gè)文件在內(nèi)存中只有一個(gè)緩沖區(qū),在向文件輸出數(shù)據(jù)時(shí),它就作為輸出緩沖區(qū),在從文件輸入數(shù)據(jù)時(shí),它就作為輸入緩沖區(qū)。圖10-2緩沖區(qū)5.文件類型指針5.文件類型指針緩沖文件系統(tǒng)中,關(guān)鍵的概念是“文件類型指針”,簡(jiǎn)稱“文件指針”。每個(gè)被使用的文件都在內(nèi)存中開(kāi)辟一個(gè)相應(yīng)的文件信息區(qū),用來(lái)存放文件的有關(guān)信息(如文件的名字、文件狀態(tài)及文件當(dāng)前位置等)。這些信息是保存在一個(gè)結(jié)構(gòu)體變量中的。該結(jié)構(gòu)體類型是由系統(tǒng)聲明的,取名為FILE。在程序中可以直接用FILE類型名定義變量。每一個(gè)FILE類型變量對(duì)應(yīng)一個(gè)文件的信息區(qū),在其中存放該文件的有關(guān)信息。例如,可以定義以下FILE類型的變量:FILEfileScore;以上定義了一個(gè)結(jié)構(gòu)體變量fileScore,用它來(lái)存放一個(gè)文件的有關(guān)信息。這些信息是在打開(kāi)一個(gè)文件時(shí)由系統(tǒng)根據(jù)文件的情況自動(dòng)放入的,在讀寫(xiě)文件時(shí)需要用到這些信息,也會(huì)修改某些信息。例如在讀一個(gè)字符后,文件信息區(qū)中的位置標(biāo)記指針的指向就要改變。5.文件類型指針一般不定義FILE類型的變量,而是設(shè)置一個(gè)指向FILE類型變量的指針變量,然后通過(guò)它來(lái)引用這些FILE類型變量。這樣使用起來(lái)方便。下面定義一個(gè)指向文件型數(shù)據(jù)的指針變量:FILE*filePointer;定義filePointer是一個(gè)指向FILE類型數(shù)據(jù)的指針變量??梢允筬ilePointer指向某一個(gè)文件的文件信息區(qū)(是一個(gè)結(jié)構(gòu)體變量),通過(guò)該文件信息區(qū)中的信息就能夠訪問(wèn)該文件。也就是說(shuō),通過(guò)文件指針變量能夠找到與它關(guān)聯(lián)的文件。如果有n個(gè)文件,應(yīng)設(shè)n個(gè)指針變量,分別指向n個(gè)FILE類型變量,以實(shí)現(xiàn)對(duì)n個(gè)文件的訪問(wèn)。為方便起見(jiàn),通常將這種指向文件信息區(qū)的指針變量簡(jiǎn)稱為指向文件的指針變量?!咀⒁狻恐赶蛭募闹羔樧兞坎⒉皇侵赶蛲獠拷橘|(zhì)上的數(shù)據(jù)文件的開(kāi)頭,而是指向內(nèi)存中的文件信息區(qū)的開(kāi)頭。10.2文件的相關(guān)操作10.2.1文件的打開(kāi)與關(guān)閉在編寫(xiě)程序時(shí),在打開(kāi)文件的同時(shí),一般都指定一個(gè)指針變量指向該文件,也就是建立起指針變量與文件之間的聯(lián)系,這樣就可以通過(guò)該指針變量對(duì)文件進(jìn)行讀寫(xiě)了。所謂“關(guān)閉”是指撤銷文件信息區(qū)和文件緩沖區(qū),使文件指針變量不再指向該文件,顯然就無(wú)法進(jìn)行對(duì)文件的讀寫(xiě)了。1.用fopen函數(shù)打開(kāi)數(shù)據(jù)文件fopen函數(shù)的調(diào)用方式為:fopen(文件名,使用文件方式);例如:fopen("score","r");表示要打開(kāi)名字為score的文件,使用文件方式為“讀入”(r代表read,即讀入)。fopen函數(shù)的返回值是指向score文件的指針(即score文件信息區(qū)的起始地址)。通常將fopen函數(shù)的返回值賦給一個(gè)指向文件的指針變量。如:FILE*filePointer;/*定義一個(gè)指向文件的指針變量filePointer*/filePointer=fopen("score","r");/*將fopen函數(shù)的返回值賦給指針變量filePointer*/1.用fopen函數(shù)打開(kāi)數(shù)據(jù)文件這樣filePointer就和文件score相聯(lián)系了,或者說(shuō)filePointer指向了score文件??梢钥闯觯诖蜷_(kāi)一個(gè)文件時(shí),通知編譯系統(tǒng)以下3個(gè)信息:需要打開(kāi)文件的名字,也就是準(zhǔn)備訪問(wèn)的文件的名字;使用文件的方式(“讀”還是“寫(xiě)”等);讓哪一個(gè)指針變量指向被打開(kāi)的文件。使用文件方式見(jiàn)下表。文件使用方式含義如果指定的文件不存在“r”(只讀)為輸入數(shù)據(jù)打開(kāi)一個(gè)文本文件出錯(cuò)“w”(只寫(xiě))為輸出數(shù)據(jù)打開(kāi)一個(gè)文本文件建立新文件“a”(追加)向文本文件尾添加數(shù)據(jù)出錯(cuò)“rb”(只讀)為輸入數(shù)據(jù)打開(kāi)一個(gè)二進(jìn)制文件出錯(cuò)“wb”(只寫(xiě))為輸出數(shù)據(jù)打開(kāi)一個(gè)二進(jìn)制文件建立新文件“ab”(追加)向二進(jìn)制文件尾添加數(shù)據(jù)出錯(cuò)“r+”(讀寫(xiě))為讀寫(xiě)打開(kāi)一個(gè)文本文件出錯(cuò)“w+”(讀寫(xiě))為讀寫(xiě)建立一個(gè)新的文本文件建立新文件“a+”(讀寫(xiě))為讀寫(xiě)打開(kāi)一個(gè)文本文件出錯(cuò)“rb+”(讀寫(xiě))為讀寫(xiě)打開(kāi)一個(gè)二進(jìn)制文件出錯(cuò)“wb+”(讀寫(xiě))為讀寫(xiě)建立一個(gè)新的二進(jìn)制文件建立新文件“ab+”(讀寫(xiě))為讀寫(xiě)打開(kāi)一個(gè)二進(jìn)制文件出錯(cuò)表10-1使用文件方式【說(shuō)明】①用r方式打開(kāi)的文件只能用于向計(jì)算機(jī)輸入而不能用作向該文件輸出數(shù)據(jù),而且該文件應(yīng)該已經(jīng)存在,并存有數(shù)據(jù),這樣程序才能從文件中讀數(shù)據(jù)。不能用r方式打開(kāi)一個(gè)并不存在的文件,否則出錯(cuò)。②用w方式打開(kāi)的文件只能用于向該文件寫(xiě)數(shù)據(jù)(即輸出文件),而不能用來(lái)向計(jì)算機(jī)輸入。如果原來(lái)不存在該文件,則在打開(kāi)文件前新建立一個(gè)以指定的名字命名的文件。如果原來(lái)已存在一個(gè)以該文件名命名的文件,則在打開(kāi)文件前先將該文件刪去,然后重新建立一個(gè)新文件。③如果希望向文件末尾添加新的數(shù)據(jù)(不希望刪除原有數(shù)據(jù)),則應(yīng)該用a方式打開(kāi)。但此時(shí)應(yīng)保證該文件已存在;否則將得到出錯(cuò)信息。打開(kāi)文件時(shí),文件讀寫(xiě)位置標(biāo)記移到文件末尾。【說(shuō)明】④用“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)的文件不被刪去,文件讀寫(xiě)位置標(biāo)記移到文件末尾,可以添加,也可以讀。⑤如果不能實(shí)現(xiàn)“打開(kāi)”的任務(wù),fopen函數(shù)將會(huì)帶回一個(gè)出錯(cuò)信息。出錯(cuò)的原因可能是:用r方式打開(kāi)一個(gè)并不存在的文件,磁盤(pán)出故障,磁盤(pán)已滿無(wú)法建立新文件等。此時(shí)fopen函數(shù)將帶回一個(gè)空指針值NULL。常用以下程序段打開(kāi)文件:if((fp=fopen("D:\\hdjd","rb")==NULL){【說(shuō)明】printf("\nerroronopenD:\\hdjdfile!");exit(0);}即先檢查打開(kāi)文件的操作有否出錯(cuò),如果有錯(cuò)就在終端上輸出erroronopenD:\\hdjdfile!。exit函數(shù)的作用是關(guān)閉所有文件,終止正在執(zhí)行的程序,待用戶檢查出錯(cuò)誤,修改后重新運(yùn)行。⑥在表10.1中有12種文件使用方式,其中有6種是在第一個(gè)字母后面加了字母b的(如rb,wb,ab,rb+,wb+,ab+),b表示二進(jìn)制方式。其實(shí)帶b和不帶b只有一個(gè)區(qū)別,即對(duì)換行的處理。【說(shuō)明】由于在C語(yǔ)言用一個(gè)'\n'即可實(shí)現(xiàn)換行,而在Windows系統(tǒng)中為實(shí)現(xiàn)換行必須要用“回車”和“換行”兩個(gè)字符,即'\r'和'\n'。因此,如果使用的是文本文件并且用w方式打開(kāi),在向文件輸出時(shí),遇到換行符'\n'時(shí),系統(tǒng)就把它轉(zhuǎn)換為'\r'和\n'兩個(gè)字符,否則在Windows系統(tǒng)中查看文件時(shí),各行連成一片,無(wú)法閱讀。同樣,如果有文本文件且用r方式打開(kāi),從文件讀入時(shí),遇到'\r'和'\n'兩個(gè)連續(xù)的字符,就把它們轉(zhuǎn)換為'\n'一個(gè)字符。如果使用的是二進(jìn)制文件,在向文件讀寫(xiě)時(shí),不需要這種轉(zhuǎn)換。加b表示使用的是二進(jìn)制文件,系統(tǒng)就不進(jìn)行轉(zhuǎn)換?!菊f(shuō)明】⑦如果用wb的文件使用方式,并不意味著在文件輸出時(shí)把內(nèi)存中按ASCII形式保存的數(shù)據(jù)自動(dòng)轉(zhuǎn)換成二進(jìn)制形式存儲(chǔ)。輸出的數(shù)據(jù)形式是由程序中采用什么讀寫(xiě)語(yǔ)句決定的。例如,用fscanf和fprintf函數(shù)是按ASCII方式進(jìn)行輸入輸出,而fread和fwrite函數(shù)是按二進(jìn)制進(jìn)行輸入輸出。在打開(kāi)一個(gè)輸出文件時(shí),是選w還是wb方式,完全根據(jù)需要,如果需要對(duì)回車符進(jìn)行轉(zhuǎn)換的,就用w,如果不需要轉(zhuǎn)換的,就用wb。帶b只是通知編譯系統(tǒng)不必進(jìn)行回車符的轉(zhuǎn)換。如果是文本文件(例如一篇文章),顯然需要轉(zhuǎn)換,應(yīng)該用w方式。如果是用二進(jìn)制形式保存的一批數(shù)據(jù),并不準(zhǔn)備供人閱讀,只是為了保存數(shù)據(jù),就不必進(jìn)行上述轉(zhuǎn)換??梢杂脀b方式。一般情況下,帶b的用于二進(jìn)制文件,常稱為二進(jìn)制方式,不帶b的用于文本文件,常稱為文本方式,從理論上說(shuō),文本文件也可以wb方式打開(kāi),但無(wú)必要?!菊f(shuō)明】⑧程序中可以使用3個(gè)標(biāo)準(zhǔn)的流文件——標(biāo)準(zhǔn)輸入流、標(biāo)準(zhǔn)輸出流和標(biāo)準(zhǔn)出錯(cuò)輸出流。系統(tǒng)已對(duì)這3個(gè)文件指定了與終端的對(duì)應(yīng)關(guān)系。標(biāo)準(zhǔn)輸入流是從終端的輸入,標(biāo)準(zhǔn)輸出流是向終端的輸出,標(biāo)準(zhǔn)出錯(cuò)輸出流是當(dāng)程序出錯(cuò)時(shí)將出錯(cuò)信息發(fā)送到終端。程序開(kāi)始運(yùn)行時(shí)系統(tǒng)自動(dòng)打開(kāi)這3個(gè)標(biāo)準(zhǔn)流文件。因此,程序編寫(xiě)者不需要在程序中用fopen函數(shù)打開(kāi)它們。所以以前我們用到的從終端輸入或輸出到終端都不需要打開(kāi)終端文件。系統(tǒng)定義了3個(gè)文件指針變量stdin,stdout和stderr,分別指向標(biāo)準(zhǔn)輸入流、標(biāo)準(zhǔn)輸出流和標(biāo)準(zhǔn)出錯(cuò)輸出流,可以通過(guò)這3個(gè)指針變量對(duì)以上3種流進(jìn)行操作,它們都以終端作為輸入輸出對(duì)象。例如程序中指定要從stdin所指的文件輸入數(shù)據(jù),就是指從終端鍵盤(pán)輸入數(shù)據(jù)。2.用fclose函數(shù)關(guān)閉數(shù)據(jù)文件在使用完一個(gè)文件后應(yīng)該關(guān)閉它,以防止它再被誤用?!瓣P(guān)閉”就是撤銷文件信息區(qū)和文件緩沖區(qū),使文件指針變量不再指向該文件,也就是文件指針變量與文件“脫鉤”,此后不能再通過(guò)該指針對(duì)原來(lái)與其相聯(lián)系的文件進(jìn)行讀寫(xiě)操作,除非再次打開(kāi),使該指針變量重新指向該文件。關(guān)閉文件用fclose函數(shù)。fclose函數(shù)調(diào)用的一般形式為:fclose(文件指針);例如:fclose(filePointer);前面曾把打開(kāi)文件(用fopen函數(shù))時(shí)函數(shù)返回的指針賦給了filePointer,現(xiàn)在把filePointer指向的文件關(guān)閉,此后filePointer不再指向該文件。2.用fclose函數(shù)關(guān)閉數(shù)據(jù)文件如果不關(guān)閉文件就結(jié)束程序運(yùn)行將會(huì)丟失數(shù)據(jù)。因?yàn)樵谙蛭募?xiě)數(shù)據(jù)時(shí),是先將數(shù)據(jù)輸出到緩沖區(qū),待緩沖區(qū)充滿后才正式輸出給文件。如果當(dāng)數(shù)據(jù)未充滿緩沖區(qū)時(shí)程序結(jié)束運(yùn)行,就有可能使緩沖區(qū)中的數(shù)據(jù)丟失。用fclose函數(shù)關(guān)閉文件時(shí),先把緩沖區(qū)中的數(shù)據(jù)輸出到磁盤(pán)文件,然后才撤銷文件信息區(qū)。有的編譯系統(tǒng)在程序結(jié)束前會(huì)自動(dòng)先將緩沖區(qū)中的數(shù)據(jù)寫(xiě)到文件,從而避免了這個(gè)問(wèn)題,但還是應(yīng)當(dāng)養(yǎng)成在程序終止之前關(guān)閉所有文件的習(xí)慣。fclose函數(shù)也帶回一個(gè)值,當(dāng)成功地執(zhí)行了關(guān)閉操作,則返回值為0;否則返回EOF(-1)。10.2.2文件的順序讀寫(xiě)文件打開(kāi)之后,就可以對(duì)它進(jìn)行讀寫(xiě)了。在順序?qū)憰r(shí),先寫(xiě)入的數(shù)據(jù)存放在文件中前面的位置,后寫(xiě)入的數(shù)據(jù)存放在文件中后面的位置。在順序讀時(shí),先讀文件中前面的數(shù)據(jù),后讀文件中后面的數(shù)據(jù)。也就是說(shuō),對(duì)順序讀寫(xiě)來(lái)說(shuō),對(duì)文件讀寫(xiě)數(shù)據(jù)的順序和數(shù)據(jù)在文件中的物理順序是一致的。順序讀寫(xiě)需要用庫(kù)函數(shù)實(shí)現(xiàn)。1.如何向文件讀寫(xiě)字符函數(shù)名調(diào)用形式功能返回值fgetcfgetc(fp)從fp指向的文件讀入一個(gè)字符讀成功,返回所讀的字符,失敗則返回文件結(jié)束標(biāo)志EOF(即-1)fputcfputc(ch,fp)把字符ch寫(xiě)到文件指針變量fp所指向的文件中輸出成功,返回值就是輸出的字符,輸出失敗,則返回EOF(即-1)對(duì)文本文件讀入或輸出一個(gè)字符的函數(shù)見(jiàn)下表。表10-2讀寫(xiě)一個(gè)字符的函數(shù)1.如何向文件讀寫(xiě)字符【例10-1】輸入一行字符,要求保存在指定的文件中。[分析]:定義save函數(shù),在該函數(shù)中,在while循環(huán)中通過(guò)fputc函數(shù)依次將鍵盤(pán)輸入的字符保存到形參fp所指向的文件中。在主函數(shù)中首先定義文件指針fp,輸入要操作的文件名,再通過(guò)fopen函數(shù)打開(kāi)該文件,并使fp指向該文件。通過(guò)調(diào)用save函數(shù)就實(shí)現(xiàn)了功能。[N-S流程圖]:輸入文件名filenamech=getchar())!='\n'fputc(ch,fp);fp=fopen(filename,"w"))!=NULL是 否輸出錯(cuò)誤,退出輸出提示:字符串保存成功!關(guān)閉fpC源程序:(文件名:li10_1.c)#include<stdlib.h>#include<stdio.h>voidsave(FILE*fp){charch;printf("請(qǐng)輸入一行要保存的內(nèi)容:\n");while((ch=getchar())!='\n')/*當(dāng)敲回車時(shí)結(jié)束循環(huán)*/{1.如何向文件讀寫(xiě)字符ch=getchar();/*接收在執(zhí)行scanf語(yǔ)句時(shí)最后輸入的回車符*/if((fp=fopen(filename,"w"))==NULL)/*打開(kāi)輸出文件并使fp指向此文件*/{printf("無(wú)法打開(kāi)此文件\n");/*如果打開(kāi)時(shí)出錯(cuò),就輸出"打不開(kāi)"的信息*/exit(0);/*終止程序*/}save(fp);/*傳遞文件指針,實(shí)現(xiàn)保存功能*/fclose(fp);/*關(guān)閉文件*/1.如何向文件讀寫(xiě)字符}運(yùn)行結(jié)果:請(qǐng)輸入所用的文件名:save.txt請(qǐng)輸入一行要保存的內(nèi)容:IloveyouChina!字符串保存成功!【例10-2】將一個(gè)磁盤(pán)文件中的內(nèi)容復(fù)制到另一個(gè)磁盤(pán)文件中。今要求將上例建立的save.txt文件中的內(nèi)容復(fù)制到另一個(gè)磁盤(pán)文件copy.txt中。1.如何向文件讀寫(xiě)字符1.如何向文件讀寫(xiě)字符[分析]:定義copy函數(shù),在該函數(shù)中,在while循環(huán)中通過(guò)fgetc函數(shù)依次讀取形參source所指向的源文件的文本內(nèi)容,然后通過(guò)fputc函數(shù)寫(xiě)入形參copys所指向的目標(biāo)文件。在主函數(shù)中首先定義文件指針source、copys,輸入要讀入的文件名以及要輸出的文件名,再通過(guò)fopen函數(shù)打開(kāi)兩個(gè)文件,最后通過(guò)調(diào)用copy函數(shù)實(shí)現(xiàn)文件復(fù)制功能。[N-S流程圖]:輸入文件名sourceFile、copyFilefp=fopen(sourceFile,"r"))!=NULL
!feof(source)ch=fgetc(source)fp=fopen(sourceFile,"r"))!=NULL是 否輸出錯(cuò)誤,退出fputc(ch,copys);putchar(ch);ch=fgetc(source)關(guān)閉source、copys是否輸出錯(cuò)誤,退出C源程序:(文件名:li10_2.c)#include<stdlib.h>#include<stdio.h>voidcopy(FILE*source,FILE*copys){charch='';printf("文件內(nèi)容是:\n");ch=fgetc(source);/*從輸入文件讀入一個(gè)字符,放在變量ch中*/while(!feof(source))/*如果未遇到輸入文件的結(jié)束標(biāo)志*/{1.如何向文件讀寫(xiě)字符fputc(ch,copys);/*將ch寫(xiě)到輸出文件中*/putchar(ch);/*將ch顯示在屏幕上*/ch=fgetc(source);/*從輸入文件讀入一個(gè)字符,放在變量ch中*/}printf("\n文件復(fù)制成功!\n");}voidmain(){FILE*source,*copys;1.如何向文件讀寫(xiě)字符charch='',sourceFile[80],copyFile[80];/*定義兩個(gè)字符數(shù)組,分別存放兩個(gè)文件名*/printf("輸入讀入文件的名字:\n");scanf("%s",sourceFile);/*輸入一個(gè)輸入文件的名字*/printf("輸入輸出文件的名字:\n");scanf("%s",copyFile);/*輸入一個(gè)輸出文件的名字*/if((source=fopen(sourceFile,"r"))==NULL)/*打開(kāi)輸入文件*/{printf("無(wú)法打開(kāi)此文件\n");1.如何向文件讀寫(xiě)字符exit(0);}if((copys=fopen(copyFile,"w"))==NULL)/*打開(kāi)輸出文件*/{printf("無(wú)法打開(kāi)此文件\n");exit(0);}copy(source,copys);fclose(source);/*關(guān)閉輸入文件*/fclose(copys); /*關(guān)閉輸出文件*/}運(yùn)行結(jié)果:輸入讀入文件的名字:save.txt輸入輸出文件的名字:copy.txt文件內(nèi)容是:IloveyouChina!文件復(fù)制成功!1.如何向文件讀寫(xiě)字符2.如何向文件讀寫(xiě)一個(gè)字符串2.如何向文件讀寫(xiě)一個(gè)字符串既然向鍵盤(pán)可以直接輸入一行字符,在屏幕上也可以直接輸出一個(gè)字符串;那么能否向文件一次性讀寫(xiě)一個(gè)字符串呢?C語(yǔ)言允許通過(guò)函數(shù)fgets和fputs一次讀寫(xiě)一個(gè)字符串,例如:fgets(str,n,fp);作用是從fp所指向的文件中讀入一個(gè)長(zhǎng)度為n-1的字符串,并在最后加一個(gè)'\0'字符,然后把這n個(gè)字符存放到字符數(shù)組str中。讀寫(xiě)一個(gè)字符串的函數(shù)見(jiàn)下表。表10-3讀寫(xiě)一個(gè)字符串的函數(shù)2.如何向文件讀寫(xiě)一個(gè)字符串表10-3讀寫(xiě)一個(gè)字符串的函數(shù)函數(shù)名調(diào)用形式功能返回值fgetsfgets(str,n,fp)從fp指向的文件讀入一個(gè)長(zhǎng)度為n-1的字符串,存放到字符數(shù)組str中讀成功,返回地址str;失敗則返回NULLfputsfputs(str,fp)把str所指向的字符串寫(xiě)到文件指針變量fp所指向的文件中輸出成功,返回0;否則返回非0【例10-3】從鍵盤(pán)輸入5個(gè)商品名稱,對(duì)它們按字母大小的順序排序,然后把排好序的商品名稱保存到磁盤(pán)文件中。[分析]:實(shí)現(xiàn)整個(gè)功能,分為3個(gè)步驟。(1)從鍵盤(pán)輸入n個(gè)字符串,存放在一個(gè)二維字符數(shù)組中,每個(gè)一維數(shù)組存放一個(gè)字符串;(2)對(duì)字符數(shù)組中的n個(gè)字符串按字母順序排序,排好序的字符串仍存放在字符數(shù)組中;(3)使用fputs函數(shù)將字符數(shù)組中的字符串寫(xiě)入文件。2.如何向文件讀寫(xiě)一個(gè)字符串C源程序:(文件名:li10_3.c)#include<stdlib.h>#include<stdio.h>voidcopy(FILE*source,FILE*copys){charch='';printf("文件內(nèi)容是:\n");ch=fgetc(source);/*從輸入文件讀入一個(gè)字符,放在變量ch中*/while(!feof(source))/*如果未遇到輸入文件的結(jié)束標(biāo)志*/{fputc(ch,copys);/*將ch寫(xiě)到輸出文件中*/putchar(ch);/*將ch顯示在屏幕上*/2.如何向文件讀寫(xiě)一個(gè)字符串ch=fgetc(source);/*從輸入文件讀入一個(gè)字符,放在變量ch中*/}printf("\n文件復(fù)制成功!\n");}voidmain(){FILE*source,*copys;charch='',sourceFile[80],copyFile[80];/*定義兩個(gè)字符數(shù)組,分別存放兩個(gè)文件名*/2.如何向文件讀寫(xiě)一個(gè)字符串printf("輸入讀入文件的名字:\n");scanf("%s",sourceFile);/*輸入一個(gè)輸入文件的名字*/printf("輸入輸出文件的名字:\n");scanf("%s",copyFile);/*輸入一個(gè)輸出文件的名字*/if((source=fopen(sourceFile,"r"))==NULL)/*打開(kāi)輸入文件*/{printf("無(wú)法打開(kāi)此文件\n");exit(0);}if((copys=fopen(copyFile,"w"))==NULL)/*打開(kāi)輸出文件*/{printf("無(wú)法打開(kāi)此文件\n");exit(0);}2.如何向文件讀寫(xiě)一個(gè)字符串copy(source,copys);fclose(source);/*關(guān)閉輸入文件*/fclose(copys);/*關(guān)閉輸出文件*/}運(yùn)行結(jié)果:輸入讀入文件的名字:save.txt輸入輸出文件的名字:copy.txt文件內(nèi)容是:IloveyouChina!文件復(fù)制成功!2.如何向文件讀寫(xiě)一個(gè)字符串【例10-4】要求從磁盤(pán)文件中讀取商品名稱,并顯示在屏幕上。[分析]:實(shí)現(xiàn)整個(gè)功能,分為3個(gè)步驟。(1)從鍵盤(pán)輸入n個(gè)字符串,存放在一個(gè)二維字符數(shù)組中,每個(gè)一維數(shù)組存放一個(gè)字符串;(2)對(duì)字符數(shù)組中的n個(gè)字符串按字母順序排序,排好序的字符串仍存放在字符數(shù)組中;(3)使用fputs函數(shù)將字符數(shù)組中的字符串寫(xiě)入文件。C源程序:(文件名:li10_4.c)#include<stdio.h>#include<stdlib.h>#defineN5voidread(FILE*fp){2.如何向文件讀寫(xiě)一個(gè)字符串chargoodsName[N][80];inti;printf("讀取到的商品名稱是:\n");for(i=0;fgets(goodsName[i],80,fp)!=NULL;i++){printf("%s",goodsName[i]);}}voidmain(){FILE*fp;if((fp=fopen("D:\\Goods\\goods.txt","r"))==NULL)//r方式打開(kāi)磁盤(pán)文件{printf("無(wú)法打開(kāi)文件!\n");exit(0);}2.如何向文件讀寫(xiě)一個(gè)字符串read(fp);fclose(fp);}運(yùn)行結(jié)果:讀取到的商品名稱是:applebananabingdundunorangexuerongrong2.如何向文件讀寫(xiě)一個(gè)字符串3.用格式化的方式讀寫(xiě)文本文件前面進(jìn)行的是字符的輸入輸出,而實(shí)際上數(shù)據(jù)的類型是豐富的。大家已很熟悉用printf函數(shù)和scanf函數(shù)向終端進(jìn)行格式化的輸入輸出,即用各種不同的格式以終端為對(duì)象輸入輸出數(shù)據(jù)。其實(shí)也可以對(duì)文件進(jìn)行格式化輸入輸出,這時(shí)就要用fprintf函數(shù)和fscanf函數(shù)。它們的作用與printf函數(shù)和scanf函數(shù)相仿,都是格式化讀寫(xiě)函數(shù)。只有一點(diǎn)不同:fprintf和fscanf函數(shù)的讀寫(xiě)對(duì)象不是終端而是文件。它們的一般調(diào)用方式為:fprintf(文件指針,格式字符串,輸出表列);fscanf(文件指針,格式字符串,輸入表列);例如:fprintf(fp,"%f,%f",ps,ai);3.用格式化的方式讀寫(xiě)文本文件它的作用是將float型變量ps和ai的值按%f的格式輸出到fp指向的文件中。同樣,用以下fsanf函數(shù)可以從磁盤(pán)文件上讀入ASCII字符:fscanf(fp,"%f,%f",ps,ai);用fprint和fcanf函數(shù)對(duì)磁盤(pán)文件讀寫(xiě),使用方便,容易理解,但由于在輸入時(shí)要將文件中的ASCII碼轉(zhuǎn)換為二進(jìn)制形式再保存在內(nèi)存變量中,在輸出時(shí)又要將內(nèi)存中的二進(jìn)制形式轉(zhuǎn)換成字符,要花費(fèi)較多時(shí)間。因此,在內(nèi)存與磁盤(pán)頻繁交換數(shù)據(jù)的情況下,最好不用fprintf和fscanf函數(shù),而用下面介紹的fread和fwrite函數(shù)進(jìn)行二進(jìn)制的讀寫(xiě)。4.用二進(jìn)制方式向文件讀寫(xiě)一組數(shù)據(jù)在程序中不僅需要一次輸人輸出一個(gè)數(shù)據(jù),而且常常需要一次輸入輸出一組數(shù)據(jù)(如數(shù)組或結(jié)構(gòu)體變量的值),C語(yǔ)言允許用fread函數(shù)從文件中讀一個(gè)數(shù)據(jù)塊,用fwrite函數(shù)向文件寫(xiě)一個(gè)數(shù)據(jù)塊。在讀寫(xiě)時(shí)是以二進(jìn)制形式進(jìn)行的。在向磁盤(pán)寫(xiě)數(shù)據(jù)時(shí),直接將內(nèi)存中一組數(shù)據(jù)原封不動(dòng)、不加轉(zhuǎn)換地復(fù)制到磁盤(pán)文件上,在讀入時(shí)也是將磁盤(pán)文件中若干字節(jié)的內(nèi)容一起讀入內(nèi)存。它們的一般調(diào)用形式為:fread(buffer,size,count,fp);fwrite(buffer,size,count,fp);4.用二進(jìn)制方式向文件讀寫(xiě)一組數(shù)據(jù)(1)buffer:是一個(gè)地址。對(duì)fread來(lái)說(shuō),它是用來(lái)存放從文件讀入的數(shù)據(jù)的存儲(chǔ)區(qū)的地址。對(duì)fwrite來(lái)說(shuō),是要把此地址開(kāi)始的存儲(chǔ)區(qū)中的數(shù)據(jù)向文件輸出(以上指的是起始地址)。(2)size:要讀寫(xiě)的字節(jié)數(shù)。(3)count:要讀寫(xiě)多少個(gè)數(shù)據(jù)項(xiàng)(每個(gè)數(shù)據(jù)項(xiàng)長(zhǎng)度為size)。(4)fp:FILE類型指針。在打開(kāi)文件時(shí)指定用二進(jìn)制文件,這樣就可以用fread和fwrite函數(shù)讀寫(xiě)任何類型的信息,例如:fread(score,4,10,fp);4.用二進(jìn)制方式向文件讀寫(xiě)一組數(shù)據(jù)其中,score是一個(gè)float型數(shù)組名(代表數(shù)組首元素地址)。這個(gè)函數(shù)從fp所指向的文件讀入10個(gè)4個(gè)字節(jié)的數(shù)據(jù),存儲(chǔ)到數(shù)組score中。【例10-5】從鍵盤(pán)輸入5名冬奧會(huì)選手的有關(guān)數(shù)據(jù),然后把它們保存到磁盤(pán)文件上去。[分析]:定義一個(gè)有5個(gè)元素的結(jié)構(gòu)體數(shù)組,用來(lái)存放5個(gè)選手的信息。從enter函數(shù)輸入5個(gè)選手的數(shù)據(jù)。用save函數(shù)實(shí)現(xiàn)向磁盤(pán)輸出選手信息。用fwrite函數(shù)一次輸出一個(gè)選手的數(shù)據(jù)。C源程序:(文件名:li10_5.c)#include<stdio.h>#defineSIZE54.用二進(jìn)制方式向文件讀寫(xiě)一組數(shù)據(jù)structathleteType{charname[30];charentries[30];intage;}athlete[SIZE];//定義全局結(jié)構(gòu)體數(shù)組athlete,包含5個(gè)選手?jǐn)?shù)據(jù)voidenter(){inti;4.用二進(jìn)制方式向文件讀寫(xiě)一組數(shù)據(jù)printf("請(qǐng)錄入選手信息:\n");for(i=0;i<SIZE;i++)//輸入SIZE個(gè)選手的數(shù)據(jù),存放在數(shù)組athlete中{printf("請(qǐng)錄入第%d個(gè)選手信息(姓名、參賽項(xiàng)目、年齡):\n",i+1);scanf("%s%s%d",athlete[i].name,athlete[i].entries,&athlete[i].age);}}4.用二進(jìn)制方式向文件讀寫(xiě)一組數(shù)據(jù)voidsave()//定義函數(shù)save,向文件輸出SIZE個(gè)選手的數(shù)據(jù){FILE*fp;inti;if((fp=fopen("athlete.dat","wb"))==NULL)//打開(kāi)輸出文件athlete.dat{printf("無(wú)法打開(kāi)文件!\n");return;}4.用二進(jìn)制方式向文件讀寫(xiě)一組數(shù)據(jù)for(i=0;i<SIZE;i++){if(fwrite(&athlete[i],sizeof(structathleteType),1,fp)!=1){printf("文件寫(xiě)入錯(cuò)誤!\n");}}printf("選手信息保存成功!\n");fclose(fp);}voidmain(){enter();save();}4.用二進(jìn)制方式向文件讀寫(xiě)一組數(shù)據(jù)運(yùn)行結(jié)果:請(qǐng)錄入選手信息:請(qǐng)錄入第1個(gè)選手信息(姓名、參賽項(xiàng)目、年齡):wudajingduandaosuhua28請(qǐng)錄入第2個(gè)選手信息(姓名、參賽項(xiàng)目、年齡):renziweiduandaosuhua25請(qǐng)錄入第3個(gè)選手信息(姓名、參賽項(xiàng)目、年齡):guailingziyoushihuaxue18請(qǐng)錄入第4個(gè)選手信息(姓名、參賽項(xiàng)目、年齡):gaotingyusuduhuabing25請(qǐng)錄入第5個(gè)選手信息(姓名、參賽項(xiàng)目、年齡):suyimingdanbanhuaxue18選手信息保存成功!4.用二進(jìn)制方式向文件讀寫(xiě)一組數(shù)據(jù)【例10-6】從二進(jìn)制文件中讀取冬奧會(huì)選手信息,然后把它們打印在屏幕上。[分析]:編寫(xiě)一個(gè)load函數(shù),從磁盤(pán)文件athlete.dat中讀二進(jìn)制數(shù)據(jù),并存放在athlete數(shù)組中。C源程序:(文件名:li10_6.c)#include<stdio.h>#defineSIZE5structathleteType{charname[30];charentries[30];intage;4.用二進(jìn)制方式向文件讀寫(xiě)一組數(shù)據(jù)for(i=0;i<SIZE;i++){//從athlete.dat文件中讀數(shù)據(jù)if(fread(&athlete[i],sizeof(structathleteType),1,fp)!=1){if(feof(fp)){fclose(fp);return;4.用二進(jìn)制方式向文件讀寫(xiě)一組數(shù)據(jù)printf("冬奧會(huì)選手信息如下:\n");printf("選手姓名\t參賽項(xiàng)目\t年齡\n");for(i=0;i<SIZE;i++){printf("%s\t%s\t%d\n",athlete[i].name,athlete[i].entries,athlete[i].age);}}voidmain(){load();print();}4.用二進(jìn)制方式向文件讀寫(xiě)一組數(shù)據(jù)運(yùn)行結(jié)果:冬奧會(huì)選手信息如下:選手姓名
參賽項(xiàng)目
年齡wudajing duandaosuhua 28renziwei duandaosuhua 25guailing ziyoushihuaxue 18gaotingyu suduhuabing 25suyiming danbanhuaxue 18【注意】(1)數(shù)據(jù)的存儲(chǔ)方式文本方式:數(shù)據(jù)以字符方式(ASCII代碼)存儲(chǔ)到文件中。如整數(shù)12,送到文件時(shí)占2個(gè)字節(jié),而不是4個(gè)字節(jié)。以文本方式保存的數(shù)據(jù)便于閱讀。二進(jìn)制方式:數(shù)據(jù)按在內(nèi)存的存儲(chǔ)狀態(tài)原封不動(dòng)地復(fù)制到文件。如整數(shù)12,送到文件時(shí)和在內(nèi)存中一樣占4個(gè)字節(jié)。(2)文件的分類文本文件(ASCII文件):文件中全部為ASCII字符。二進(jìn)制文件:按二進(jìn)制方式把在內(nèi)存中的數(shù)據(jù)復(fù)制到文件的,稱為二進(jìn)制文件,即映像文件。(3)文件的打開(kāi)方式文本方式:不帶b的方式,讀寫(xiě)文件時(shí)對(duì)換行符進(jìn)行轉(zhuǎn)換。二進(jìn)制方式:帶b的方式,讀寫(xiě)文件時(shí)對(duì)換行符不進(jìn)行轉(zhuǎn)換。(4)文件讀寫(xiě)函數(shù)文本讀寫(xiě)函數(shù):用來(lái)向文本文件讀寫(xiě)字符數(shù)據(jù)的函數(shù)(如fgetc,fgets,fputc,fputs,fscanf,fprintf等)。二進(jìn)制讀寫(xiě)函數(shù):用來(lái)向二進(jìn)制文件讀寫(xiě)二進(jìn)制數(shù)據(jù)的函數(shù)(如getw,putw,fread,fwrite等)。10.2.3文件的隨機(jī)讀寫(xiě)
對(duì)文件進(jìn)行順序讀寫(xiě)比較容易理解,也容易操作,但有時(shí)效率不高,例如參與冬奧會(huì)的各國(guó)選手將近3000人,如果要查詢最后一名選手是誰(shuí),必須先逐個(gè)讀取除倒數(shù)第一以外的所有選手信息以后,才能讀入最后一名選手。這樣效率太低,讓人無(wú)法忍受。隨機(jī)訪問(wèn)不是按數(shù)據(jù)在文件中的物理位置次序進(jìn)行讀寫(xiě),而是可以對(duì)任何位置上的數(shù)據(jù)進(jìn)行訪問(wèn),顯然這種方法比順序訪問(wèn)效率高得多。1.文件位置標(biāo)記及其定位(1)文件位置標(biāo)記前已介紹,為了對(duì)讀寫(xiě)進(jìn)行控制,系統(tǒng)為每個(gè)文件設(shè)置了一個(gè)文件讀寫(xiě)位置標(biāo)記(簡(jiǎn)稱文件位置標(biāo)記或文件標(biāo)記接下來(lái)要讀寫(xiě)的下一個(gè)字符的位置,用來(lái)指示“接下來(lái)要讀寫(xiě)的下一個(gè)字符的位置”。一般情況下,在對(duì)字符文件進(jìn)行順序讀寫(xiě)時(shí),文件位置標(biāo)記指向文件開(kāi)頭,這時(shí)如果對(duì)文件進(jìn)行讀的操作,就讀第1個(gè)字符,然后文件位置標(biāo)記向后移一個(gè)位置,在下一次執(zhí)行讀的操作時(shí),就將位置標(biāo)記指向的第2個(gè)字符讀入。依此類推,遇到文件尾結(jié)束。10.2.3文件的隨機(jī)讀寫(xiě)
如果是順序?qū)懳募?,則每寫(xiě)完一個(gè)數(shù)據(jù)后,文件位置標(biāo)記順序向后移一個(gè)位置,然后在下一次執(zhí)行寫(xiě)操作時(shí)把數(shù)據(jù)寫(xiě)入位置標(biāo)記所指的位置。直到把全部數(shù)據(jù)寫(xiě)完,此時(shí)文件位置標(biāo)記在最后一個(gè)數(shù)據(jù)之后??梢愿鶕?jù)讀寫(xiě)的需要,人為地移動(dòng)文件位置標(biāo)記的位置。文件位置標(biāo)記可以向前移、向后移,移到文件頭或文件尾,然后對(duì)該位置進(jìn)行讀寫(xiě),顯然這就不是順序讀寫(xiě)了,而是隨機(jī)讀寫(xiě)。對(duì)流式文件既可以進(jìn)行順序讀寫(xiě),也可以進(jìn)行隨機(jī)讀寫(xiě)。關(guān)鍵在于控制文件的位置標(biāo)記。如果文件位置標(biāo)記是按字節(jié)位置順序移動(dòng)的,就是順序讀寫(xiě)。如果能將文件位置標(biāo)記按需要移動(dòng)到任意位置,就可以實(shí)現(xiàn)隨機(jī)讀寫(xiě)。所謂隨機(jī)讀寫(xiě),是指讀寫(xiě)完上一個(gè)字符(字節(jié))后,并不一定要讀寫(xiě)其后續(xù)的字符(字節(jié)),而可以讀寫(xiě)文件中任意位置上所需要的字符(字節(jié))。即對(duì)文件讀寫(xiě)數(shù)據(jù)的順序和數(shù)據(jù)在文件中的物理順序一般是不一致的??梢栽谌魏挝恢脤?xiě)入數(shù)據(jù),在任何位置讀取數(shù)據(jù)。(2)文件位置標(biāo)記的定位可以強(qiáng)制使文件位置標(biāo)記指向人們指定的位置??梢杂靡韵潞瘮?shù)實(shí)現(xiàn)。①
用rewind函數(shù)使文件位置標(biāo)記指向文件開(kāi)頭rewind函數(shù)的作用是使文件位置標(biāo)記重新返回文件的開(kāi)頭,此函數(shù)沒(méi)有返回值。10.2.3文件的隨機(jī)讀寫(xiě)【例10-7】有一個(gè)磁盤(pán)文件,內(nèi)有一些信息。要求將它的內(nèi)容顯示在屏幕上,同時(shí)把它復(fù)制到另一文件上。[分析]:分別實(shí)現(xiàn)以上兩個(gè)任務(wù)都不困難,但是把二者連續(xù)做,就會(huì)出現(xiàn)問(wèn)題,因?yàn)樵谧x入完文件內(nèi)容后,文件位置標(biāo)記已指到文件的末尾,如果再接著讀數(shù)據(jù),就遇到文件結(jié)束標(biāo)志EOF,feof函數(shù)的值等于1(真),無(wú)法再讀數(shù)據(jù)。必須在程序中用rewind函數(shù)使位置指針?lè)祷匚募拈_(kāi)頭。C源程序:(文件名:li10_7.c)#include<stdio.h>#include<stdlib.h>voidprint(FILE*fp){ printf("原始文件的內(nèi)容是:\n"); while(!feof(fp)) { putchar(getc(fp)); //逐個(gè)讀入字符并輸出到屏幕
} putchar('\n'); //輸出一個(gè)換行
}10.2.3文件的隨機(jī)讀寫(xiě)voidcopy(FILE*fp1,FILE*fp2){ while(!feof(fp1)) {putc(getc(fp1),fp2); //從文件頭重新逐個(gè)讀字符,輸出到新文件
} printf("文件復(fù)制成功!\n");}voidmain(){ FILE*fp1,*fp2; if((fp1=fopen("source.txt","r"))==NULL){printf("無(wú)法打開(kāi)原始文件!\n"); exit(0)}10.2.3文件的隨機(jī)讀寫(xiě) print(fp1); rewind(fp1); if((fp2=fopen("copy.txt","w"))==NULL){ printf("無(wú)法打開(kāi)新文件!\n"); exit(0);}copy(fp1,fp2); fclose(fp1); fclose(fp2);}運(yùn)行結(jié)果:原始文件的內(nèi)容是:BeiJing2022-->TotheFutureTogether
文件復(fù)制成功!10.2.3文件的隨機(jī)讀寫(xiě)②
用fseek函數(shù)改變文件位置標(biāo)記fseek函數(shù)的調(diào)用形式為:fseek(文件類型指針,位移量,起始點(diǎn))“起始點(diǎn)”用0,1或2代替,0代表“文件開(kāi)始位置",1為“當(dāng)前位置”,2為“文件末尾位置”。C標(biāo)準(zhǔn)指定的名字如下表所示。表10-4
C標(biāo)準(zhǔn)指定的名字起始點(diǎn)名字用數(shù)字代表文件開(kāi)始位置SEEK_SET0文件當(dāng)前位置SEEK_CUR1文件末尾位置SEEK_END210.2.3文件的隨機(jī)讀寫(xiě)“位移量”指以“起始點(diǎn)”為基點(diǎn),向前移動(dòng)的字節(jié)數(shù)。位移量應(yīng)是long型數(shù)據(jù)(在數(shù)字的末尾加一個(gè)字母L,就表示是long型)。fseek函數(shù)一般用于二進(jìn)制文件。下面是fseek函數(shù)調(diào)用的幾個(gè)例子:fseek(fp,100L,0); 將文件位置標(biāo)記向前移到離文件開(kāi)頭100個(gè)字節(jié)處fseek(fp,50L,1); 將文件位置標(biāo)記向前移到離當(dāng)前位置50個(gè)字節(jié)處fseek(fp,-10L,2); 將文件位置標(biāo)記從文件末尾處向后退10個(gè)字節(jié)2.隨機(jī)讀寫(xiě)有了rewind和fseek函數(shù),就可以實(shí)現(xiàn)隨機(jī)讀寫(xiě)了。通過(guò)下面簡(jiǎn)單的例子可以了解怎樣進(jìn)行隨機(jī)讀寫(xiě)?!纠?0-8】從二進(jìn)制文件中讀取冬奧會(huì)選手信息(奇數(shù)位),然后把它們打印在屏幕上。[分析]:按“二進(jìn)制只讀”的方式打開(kāi)指定的磁盤(pán)文件,準(zhǔn)備從磁盤(pán)文件中讀取選手?jǐn)?shù)據(jù);)將文件位置標(biāo)記指向文件的開(kāi)頭,然后從磁盤(pán)文件讀入一個(gè)選手的信息,并把它顯示在屏幕上;再將文件位置標(biāo)記指向文件中第3,5個(gè)選手的數(shù)據(jù)區(qū)的開(kāi)頭,從磁盤(pán)文件讀入相應(yīng)選手的信息,并把它顯示在屏幕上。10.2.3文件的隨機(jī)讀寫(xiě)C源程序:(文件名:li10_8.c)#include<stdio.h>#include<stdlib.h>#defineSIZE5structathleteType{ charname[30]; charentries[30]; intage;}athlete[SIZE]; //定義全局結(jié)構(gòu)體數(shù)組athlete,包含5個(gè)選手?jǐn)?shù)據(jù)
voidread(FILE*fp){ inti; printf("冬奧會(huì)選手信息如下:\n"); printf("選手姓名\t參賽項(xiàng)目\t年齡\n");10.2.3文件的隨機(jī)讀寫(xiě)
溫馨提示
- 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ì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 《七 小小運(yùn)動(dòng)會(huì):7、6加幾》(教案)-一年級(jí)上冊(cè)數(shù)學(xué) 青島版
- 五年級(jí)下冊(cè)數(shù)學(xué)教案-4.2 分?jǐn)?shù)加減法的簡(jiǎn)算 ︳西師大版
- 勞動(dòng)合同管理臺(tái)賬(2025年版)
- 二年級(jí)下冊(cè)數(shù)學(xué)教案-4.1 《長(zhǎng)方形和正方形的特征》 ︳西師大版
- 一年級(jí)上冊(cè)數(shù)學(xué)教案-4 14,15減幾 ︳西師大版
- 二年級(jí)下冊(cè)數(shù)學(xué)教案-租船3 北師大版
- 模擬試卷一(原卷版+解析版)-三年級(jí)語(yǔ)文上學(xué)期期末全真模擬卷(部編版五四制)
- 人教版三年級(jí)上冊(cè)期末考試數(shù)學(xué)試卷-
- 《十一月四日風(fēng)雨大作》歷年中考古詩(shī)欣賞試題匯編(截至2023年)
- 2025屆黑龍江佳木斯一中高三上學(xué)期五調(diào)地理試題及答案
- 稅法最全課件完整版ppt教程整套教學(xué)講義(最新)
- 2022年南京信息職業(yè)技術(shù)學(xué)院職業(yè)適應(yīng)性測(cè)試模擬試題及答案解析
- 英語(yǔ)演講素材OfMiceandMen課件
- 廣東佛山祖廟導(dǎo)游詞
- 硬筆書(shū)法紙可打印
- 正丁烷的理化性質(zhì)及危險(xiǎn)特性表
- 入團(tuán)志愿書(shū)(2016版本)(可編輯打印標(biāo)準(zhǔn)A4) (1)
- 《朝天子詠喇叭》教學(xué)設(shè)計(jì)
- 《金融學(xué)基礎(chǔ)》實(shí)訓(xùn)手冊(cè)
- 稅收基礎(chǔ)知識(shí)考試題庫(kù)
- 1t燃?xì)庹羝仩t用戶需求(URS)(共13頁(yè))
評(píng)論
0/150
提交評(píng)論