版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)
文檔簡介
第九章文件第九章文件本章學(xué)習(xí)目標(biāo)理解文件概念與類型:掌握文件的基本概念,包括文件的定義、類型。掌握文件的打開與關(guān)閉:學(xué)會使用C標(biāo)準(zhǔn)庫中的函數(shù)來打開和關(guān)閉文件,理解不同模式的使用場景及影響。實現(xiàn)文件的讀寫操作:能夠運用fread(),fwrite(),fscanf(),fprintf()等函數(shù)進行文件數(shù)據(jù)的讀取與寫入,理解緩沖區(qū)的概念及其在文件操作中的作用。掌握文件的定位與錯誤處理:學(xué)會使用fseek()函數(shù)進行文件內(nèi)部的隨機訪問和位置定位,理解文件指針的作用。9.1文件與隱私保護我們現(xiàn)在身處互聯(lián)網(wǎng)時代,每天都會與各種信息系統(tǒng)進行交互,在此過程中,會在互聯(lián)網(wǎng)上留下各種信息,文件作為信息存儲和交換的基本單位,承載著個人、企業(yè)乃至國家的重要數(shù)據(jù)。
互聯(lián)網(wǎng)的普及極大地推動了信息的自由流動與共享,卻也使得個人隱私保護面臨前所未有的挑戰(zhàn)。社交平臺、在線購物、健康追蹤應(yīng)用……每一項便捷服務(wù)的背后,都是對個人數(shù)據(jù)的大量收集與處理。
歷史上發(fā)生過很多重大的數(shù)據(jù)隱私泄露事件。例如臭名昭著的美國“棱鏡門”事件,美國政府利用其先進的信息技術(shù)對諸多國家的首腦、政府、官員和個人都進行了監(jiān)控,收集了包羅萬象的海量數(shù)據(jù),并從這些海量數(shù)據(jù)中挖掘出其所需要的各種信息。還有發(fā)生在2008年Facebook數(shù)據(jù)泄露事件,超過5000萬用戶的個人信息被不當(dāng)獲取,引發(fā)了全球?qū)τ跀?shù)據(jù)安全與隱私保護的深刻反思。9.1文件與隱私保護作為學(xué)習(xí)計算機的學(xué)生,我們在提高自己技術(shù)的路上,應(yīng)該把保護隱私當(dāng)作一個很重要的規(guī)則來堅持。這意味著在我們設(shè)計和編程時,要一直尊重別人的隱私,只收集和使用所需要的最少的信息,還要運用密碼技術(shù)來保護信息安全。我們也應(yīng)該在開始設(shè)計項目時就考慮到保護隱私的方法,確保我們做的產(chǎn)品默認就是保護用戶隱私的。我們要跟著法律走,比如要了解《中國的個人信息保護法》、歐盟的數(shù)據(jù)保護規(guī)則GDPR等等,同時在我們嘗試新技術(shù)時也要考慮到道德問題,避免濫用技術(shù)導(dǎo)致的問題。另外,我們需要不斷學(xué)習(xí),適應(yīng)保護隱私的新挑戰(zhàn),通過教育用戶增加大家保護隱私的意識。總的來說,作為未來的科技工作者,我們要記住我們對社會的責(zé)任,要確保隨著科技進步,人們的隱私權(quán)也同時得到保護,一起創(chuàng)造一個安全,尊重隱私的數(shù)字世界。9.2文件的概念與分類在正式學(xué)習(xí)C語言操作文件的方法之前,我們需要從計算機的視角來了解什么是文件。本節(jié)將介紹在計算機中,文件的存儲方式,主要包括文本文件和二進制文件兩種,接著介紹在計算機中文件的存儲結(jié)構(gòu)以及文件的打開模式等知識。9.2.1文本文件與二進制文件文本文件在大多數(shù)系統(tǒng)中,文件類型是多樣的。例如,在程序設(shè)計范疇中,你需要和源文件、目標(biāo)文件和可執(zhí)行文件打交道,每種文件都有其獨特的表示方式。當(dāng)你用文件存儲程序中要用到的數(shù)據(jù)時,這個文件通常都會包含文本,所以稱之為文本文件(textfile)。你可以將文本文件看作存儲在永久介質(zhì)上的字符序列,并通過文件名來標(biāo)識這些文件。文件名及文件包含的字符之間的關(guān)系和變量名及其內(nèi)容之間的關(guān)系是一樣的。9.2.1文本文件與二進制文件文本文件文本文件以字符為單位存儲數(shù)據(jù),使用的字符編碼通常是ASCII或Unicode,數(shù)據(jù)以可讀的文本形式存儲,包括字母、數(shù)字、符號和控制字符等。文本文件可以通過文本編輯器或命令行文本處理工具直接查看和編輯。每行文本由一個換行符(例如\n)結(jié)尾,通常用于表示行結(jié)束。例如創(chuàng)建一個新的文本文件witches.txt,其內(nèi)容出自《麥克白》的兩行語句:Double,doubletoilandtrouble:Fireburnandcauldronbubble.9.2.1文本文件與二進制文件文本文件大家會很容易認為witches.txt是由兩行組成的。但從計算機的角度來說,文本文件是由一維的字符序列表示的,除了可見的打印字符外,文件還包含行終止符'\n'。所以,更準(zhǔn)確地來說,文件witches.txt是以如下形式出現(xiàn)的:文本文件除了以上的txt格式的文件以外,還有常見的CSV文件、XML文件和HTML文件等。Double,doubletoilandtrouble:\nFireburnandcauldronbubble.\n9.2.1文本文件與二進制文件文本文件文本文件除了以上的txt格式的文件以外,還有常見的CSV文件、XML文件和HTML文件等。文本文件的主要特點是可視的,容易被人類讀取和理解,適用于存儲文本數(shù)據(jù),例如文檔、配置文件、源代碼等。但如果內(nèi)容較大時,相較于二進制文件,可能占用更多的存儲空間。至于原因,將在后面介紹完二進制文件后再做講解。9.2.1文本文件與二進制文件二進制文件二進制文件與文本文件不同的是,它以字節(jié)為單位存儲數(shù)據(jù),不依賴于字符編碼,直接按照二進制格式存儲。數(shù)據(jù)以機器可讀的形式存儲,包括數(shù)字、二進制位序列等。二進制文件的例子包括圖像文件(例如.jpg、.png)、音頻文件(例如.mp3、.wav)、視頻文件(例如.mp4、.avi)、可執(zhí)行程序等。二進制文件無法通過文本編輯器直接查看和編輯,需要特定的程序解析,沒有行結(jié)束符的概念,數(shù)據(jù)以連續(xù)的字節(jié)流存儲。二進制文件的主要特點是不能直接被人類讀取和理解,需要特定的程序進行解析,比如查看圖片需要圖片讀取軟件,.mp3格式文件需要音樂播放器,.mp4文件需要視頻播放器等。二進制文件適合存儲非文本格式的數(shù)據(jù),例如圖像、音頻、視頻等。在同等內(nèi)容情況下,相較于文本文件,使用二進制文件存儲需要的存儲空間更小。9.2.1文本文件與二進制文件二進制文件現(xiàn)在來舉例說明。假設(shè)有一個變量定義如下:shortinta=135;如果現(xiàn)需要將變量a持久化存儲到文件中,如果采用二進制的方式存儲,需要2個字節(jié)的存儲空間,存儲空間結(jié)構(gòu)見表9-1:0000000010000111表9-1二進制文件存儲變量a占2個字節(jié)存儲空間9.2.1文本文件與二進制文件二進制文件如果采用文本文件的方式存儲變量a,則需要3個字節(jié)的存儲空間,存儲空間結(jié)構(gòu)見表9-2:那么如果變量a的值變?yōu)?357,兩種存儲方式所占內(nèi)存空間又會發(fā)生什么變化呢?對于二進制文件,存儲135和1357所占的存儲空間是一樣的,都是2個字節(jié)字符’1‘’3‘’5十進制ASCII值495153二進制ASCII值001100010011001100110101表9-2文本文件存儲變量a占3個字節(jié)存儲空間9.2.1文本文件與二進制文件二進制文件實際存儲效果如下,存儲空間結(jié)構(gòu)見表9-3:如果采用文本文件的方式存儲變量a=1357,則需要4個字節(jié)的存儲空間,存儲空間結(jié)構(gòu)見表9-4:0000010101001101表9-3二進制文件存儲變量1357字符‘1’‘3’‘5’‘7’十進制ASCII值49515355二進制ASCII值00110001001100110011010100110111表9-4二進制文件存儲變量13579.2.1文本文件與二進制文件二進制文件綜上可以看出,二進制文件和文本文件各有優(yōu)缺點。文本文件以字符為單位存儲,便于人類閱讀和編輯;而二進制文件以字節(jié)為單位存儲,適合機器處理。文本文件使用字符編碼表示數(shù)據(jù);而二進制文件直接按照二進制格式存儲數(shù)據(jù)。文本文件以可讀的文本形式存儲數(shù)據(jù),包括字母、數(shù)字、符號等;而二進制文件以機器可讀的形式存儲數(shù)據(jù),不依賴于字符編碼。文本文件可以通過文本編輯器直接查看和編輯;而二進制文件需要特定的程序進行解析和處理。9.2.2文本的存儲結(jié)構(gòu)在C語言中,物理文件內(nèi)容是什么,數(shù)據(jù)其存儲結(jié)構(gòu)本質(zhì)上是一系列字節(jié)構(gòu)成的序列。計算機在存取文件內(nèi)容時,也是以字節(jié)為單位的,這些字節(jié)可以被組織成任何形式的數(shù)據(jù),例如文本、圖像、音頻等。C語言并不直接關(guān)心文件的內(nèi)容是什么,它只是將文件視為一系列字節(jié)的集合,程序員可以根據(jù)需要以不同的方式讀取和處理這些字節(jié)。輸入/輸出的數(shù)據(jù)流僅受程序控制而不受物理符號(如回車換行符)的控制。所以從C語言的角度來看文件,又將其稱為流式文件。文件的存儲結(jié)構(gòu)通常由文件系統(tǒng)來管理,文件系統(tǒng)會將文件存儲在磁盤或其他存儲介質(zhì)上,并記錄文件的元數(shù)據(jù)(如文件名、大小、權(quán)限等)。在C語言中,文件操作函數(shù)允許程序員以字節(jié)流的形式讀取和寫入文件,這樣就可以對文件進行各種操作,而不必考慮文件的具體存儲結(jié)構(gòu)。9.2.2文本的存儲結(jié)構(gòu)通常情況下,數(shù)據(jù)必須按照存入時的類型進行讀取,才能正確還原其原始形態(tài)。以文本文件為例,如果使用非字符類型的方式進行讀取,可能會導(dǎo)致讀取出的數(shù)據(jù)失真。因此,文件的寫入和讀取必須保持一致,遵循同一種文件格式,并明確規(guī)定每個字節(jié)的類型和數(shù)據(jù)內(nèi)容。許多文件都遵循公開的標(biāo)準(zhǔn)格式,比如bmp、jpg和mp3等,通常還規(guī)定了相應(yīng)文件頭的格式。要正確讀取文件中的數(shù)據(jù),必須首先了解文件頭的格式和內(nèi)容。只有正確解析文件頭的內(nèi)容,才能準(zhǔn)確讀取文件頭后面存儲的數(shù)據(jù)內(nèi)容。許多應(yīng)用軟件都支持這些類型文件的讀取和寫入操作。這就是計算機有各式各樣的文件的原因。總之,C語言中文件的存儲結(jié)構(gòu)本質(zhì)上是字節(jié)序列,而文件系統(tǒng)負責(zé)管理這些字節(jié)的存儲和組織。程序員可以利用C語言提供的文件操作函數(shù)來讀取和寫入這些字節(jié),從而實現(xiàn)對文件的各種操作。9.3文件指數(shù)與文件操作函數(shù)9.3.1文件指針的定義在C語言中,*file是一個文件指針,文件指針是一個指向FILE類型結(jié)構(gòu)體的指針,用于跟蹤文件在內(nèi)存中的位置以及記錄文件的狀態(tài)信息。FILE結(jié)構(gòu)體是由C標(biāo)準(zhǔn)庫定義的,用于表示打開的文件。文件指針提供了一種機制,允許程序跟蹤文件在內(nèi)存中的位置,以便進行讀取和寫入操作。它類似于書中的書簽,標(biāo)記著當(dāng)前讀寫位置。通過移動文件指針,程序可以控制文件的讀取和寫入行為,定位到文件的不同位置進行操作。文件指針的基本功能包括跟蹤文件位置,文件指針記錄了文件中當(dāng)前的讀寫位置??刂莆募?,通過移動文件指針,可以定位到文件的不同位置進行讀取或?qū)懭氩僮?。狀態(tài)管理,文件指針可以用于檢查文件是否已經(jīng)結(jié)束(EOF),以及在讀寫操作中出現(xiàn)的錯誤情況。9.3文件指數(shù)與文件操作函數(shù)9.3.1文件指針的定義在C語言中,當(dāng)你打開一個文件時,操作系統(tǒng)會為該文件分配一個文件描述符,并返回一個指向該文件描述符的文件指針。這個文件指針會被用于后續(xù)對文件的操作。文件指針的使用是文件操作的關(guān)鍵,它允許程序員以字節(jié)流的形式對文件進行讀寫,并且通過控制文件指針的位置來實現(xiàn)對文件內(nèi)容的定位和操作。9.3文件指數(shù)與文件操作函數(shù)文件指針的定義在C語言中,可以通過聲明一個指向FILE類型的指針來定義文件指針。FILE類型是C標(biāo)準(zhǔn)庫中定義的結(jié)構(gòu)體類型,用于表示打開的文件。下面是定義文件指針的一般語法:1.#include<stdio.h>2.FILE*file_pointer;FILE是C標(biāo)準(zhǔn)庫中定義的結(jié)構(gòu)體類型,而file_pointer是一個指向FILE類型的指針變量。一旦定義了文件指針,你就可以將其用于打開、讀取和寫入文件,以及對文件進行其他操作。關(guān)于文件指針如何使用以及操作文件,將在后續(xù)的內(nèi)容進行講解。9.3文件指數(shù)與文件操作函數(shù)9.3.2文件操作函數(shù)介紹文件操作函數(shù)是用于在C語言中處理文件的函數(shù)集合。這些函數(shù)允許程序員打開、讀取、寫入和關(guān)閉文件,以及在文件中定位數(shù)據(jù)。通過文件操作函數(shù),程序可以從外部文件中讀取數(shù)據(jù),將數(shù)據(jù)寫入文件,或者對文件進行修改和管理。這些函數(shù)提供了對文件系統(tǒng)的訪問接口,使得程序能夠在文件級別上進行數(shù)據(jù)處理,從而實現(xiàn)數(shù)據(jù)的持久化存儲和處理。文件操作提供了豐富的功能來滿足不同的文件處理需求。通過合理使用這些函數(shù),程序員可以實現(xiàn)文件的讀取、寫入、定位和管理,從而實現(xiàn)對文件數(shù)據(jù)的有效處理和操作。表9-5是本書需要介紹的文件操作函數(shù):9.3文件指數(shù)與文件操作函數(shù)文件操作函數(shù)簡介分類函數(shù)名功能簡介文件的讀取與關(guān)閉
fopen()打開一個文件,并返回一個文件指針fclose()關(guān)閉之前打開的文件文本文件的讀取
fgetc()從文件中讀取一個字符,并將文件指針向后移動一個字符位置fgets()從文件中讀取一行字符串fscanf()文件中格式化讀取數(shù)據(jù),類似于scanf函數(shù)文本文件的寫入
fputc()向文件寫入一個字符fputs()向文件寫入一個字符串表9-5常見文件操作函數(shù)9.3文件指數(shù)與文件操作函數(shù)文件操作函數(shù)簡介分類函數(shù)名功能簡介文本文件的寫入fprintf()向文件寫入格式化數(shù)據(jù),類似于printf函數(shù)二進制文件的讀取fread()以二進制方式讀取指定數(shù)量的數(shù)據(jù)項,并將它們存儲到內(nèi)存中的緩沖區(qū)中二進制文件的寫入fwrite()以二進制方式將數(shù)據(jù)項從內(nèi)存緩沖區(qū)寫入到文件中表9-5續(xù)
常見文件操作函數(shù)9.4
文件的打開與關(guān)閉9.4.1fopen()函數(shù)不論需要操作的文件對象是文本文件還是二進制文件,在使用文件之前,都必須打開文件。fopen()函數(shù)是C語言stdio.h標(biāo)準(zhǔn)庫中用于打開文件的標(biāo)準(zhǔn)函數(shù)之一。它提供了一種方法來創(chuàng)建一個文件流,并將其與特定文件相關(guān)聯(lián),以便后續(xù)的讀取或?qū)懭氩僮鳌F浜瘮?shù)原型如下:FILE*fopen(constchar*filename,constchar*mode);fopen()函數(shù)如果調(diào)用成功,其返回值是一個指向文件流的指針(FILE*類型),如果調(diào)用失敗,則會返回一個”NULL”值。fopen()函數(shù)有兩個形參:filename表示要打開的文件的名稱,可以是相對路徑或絕對路徑;mode表示以什么模式打開文件,其取值參考表9-6:9.4
文件的打開與關(guān)閉9.4.1fopen()函數(shù)字符含義“r”只讀模式,打開文件用于讀取,如果文件不存在,則打開失敗“w”寫入模式,創(chuàng)建一個新文件用于寫入如果文件已存在,則刪除其內(nèi)容,若文件不存在則創(chuàng)建“a”追加模式,打開文件用于寫入,如果文件不存在則創(chuàng)建。新數(shù)據(jù)將被追加到文件的末尾“r+”讀寫模式,打開文件用于讀取和寫入“w+”讀寫模式,創(chuàng)建一個新文件用于讀取和寫入,如果文件已存在,則刪除其內(nèi)容“a+”讀寫模式,打開文件用于讀取和追加寫入,如果文件不存在則創(chuàng)建“b”可以與上面的字符串進行組合,表示打開二進制文件表9-6文件打開方式9.4
文件的打開與關(guān)閉9.4.1fopen()函數(shù)例如,現(xiàn)在我們在計算機的C盤中創(chuàng)建一個名為test.txt的文本文件,并以只讀的模式打開該文件,代碼如下:FILE*fp;fp=fopen(“C://test.txt”,“r”);如果需要打開一個二進制文件呢?在Windows系統(tǒng)中,二進制文件一般都是以.bin結(jié)尾的。下面我們在C盤中創(chuàng)建一個名為test.bin的二進制文件,同樣以只讀的方式打開該文件,代碼需要修改為::FILE*fp;fp=fopen(“C://test.bin”,“rb”);9.4
文件的打開與關(guān)閉9.4.2fclose()函數(shù)在使用fopen()打開文件創(chuàng)建文件指針后,會占用一定的計算機內(nèi)存空間,如果在使用該文件后,沒有及時關(guān)閉,可能會導(dǎo)致文件內(nèi)容丟失或損壞,并且會造成計算機資源的浪費,嚴(yán)重時還會導(dǎo)致計算機崩潰。為了避免這個問題,C語言提供了用于關(guān)閉文件流的函數(shù)fclose(),用于釋放文件資源。以下是fclose()函數(shù)原型:intfclose(FILE*stream);如果文件被成功關(guān)閉,將會返回0,如果文件關(guān)閉失敗,則會返回一個非0值。該函數(shù)有一個形參stream,它是一個指向FILE結(jié)構(gòu)的指針。在關(guān)閉文件流后,不能再對其進行任何讀取或?qū)懭氩僮?,使用fclose()函數(shù)是確保文件數(shù)據(jù)完整性的重要步驟,因為它會將所有緩沖區(qū)中的數(shù)據(jù)寫入到文件中,避免數(shù)據(jù)丟失或損壞的風(fēng)險。9.4
文件的打開與關(guān)閉以下是一個簡單的關(guān)于fclose()函數(shù)的操作案例:FILE*fp;fp=fopen(“C://test.txt”,“r”);fclose(fp);//關(guān)閉文件流9.4.3打開文件的錯誤異常處理在實際的文件操作編碼中,在使用fopen()函數(shù)和fclose()后,一般需要對其返回值進行驗證,以確保文件是否正常打開或是關(guān)閉。以下案例演示了常用的異常處理方式:9.4
文件的打開與關(guān)閉9.4.3打開文件的錯誤異常處理在實際的文件操作編碼中,在使用fopen()函數(shù)和fclose()后,一般需要對其返回值進行驗證,以確保文件是否正常打開或是關(guān)閉。以下案例演示了常用的異常處理方式:【例9.1】文件異常處理1 #include<stdio.h>2 intmain(){3 FILE*file;4
5 //打開文件"test.txt"用于寫入6 file=fopen("C:\\test.txt","r");7 if(file==NULL){8 perror("文件打開錯誤");9 return1;10 }else{11 printf("文件打開成功!\n");12 }13//關(guān)閉文件流14 if(fclose(file)==EOF){15 perror("文件關(guān)閉錯誤");16 return1;17 }else{9.4
文件的打開與關(guān)閉18 printf("文件關(guān)閉成功!\n");19 }20
21 return0;22 }如果文件打開和關(guān)閉成功,程序運行結(jié)果如下:文件打開成功!文件關(guān)閉成功!如果文件不存在,打開失敗,程序運行結(jié)果如下:文件打開錯誤:Nosuchfileordirectory9.4
文件的打開與關(guān)閉有細心的同學(xué)可能發(fā)現(xiàn)案例中出現(xiàn)了一個陌生的函數(shù)perror(),運行結(jié)果中“Nosuchfileordirectory”的輸出結(jié)果就是perror檢查調(diào)用fopen()失敗時檢測出的錯誤,表示系統(tǒng)中沒有該路徑的文件。perror是一個C標(biāo)準(zhǔn)庫函數(shù),用于將上一個函數(shù)調(diào)用失敗的原因輸出到標(biāo)準(zhǔn)錯誤流(stderr)。在調(diào)用可能失敗的系統(tǒng)操作(如打開文件、讀寫文件、分配內(nèi)存等)后,我們可以使用perror函數(shù)來檢查錯誤并將錯誤消息輸出到標(biāo)準(zhǔn)錯誤流。這對于調(diào)試和診斷程序錯誤非常有用,特別是在開發(fā)期間或者在需要詳細錯誤信息的情況。9.5
讀取文本文件現(xiàn)在我們已經(jīng)學(xué)會了如何打開和關(guān)閉一個文件。現(xiàn)在開始學(xué)習(xí)文件的讀取,文件的讀取方式分為文本文件的讀取和二進制文件的讀取,本節(jié)將介紹文本文件的三種讀取方式:按字符讀取fgetc(),按字符串讀取fgets()和按格式化方式讀取fscanf()。9.5.1
按字符讀取fgetc()函數(shù)函數(shù)fgetc()用于從一個以只讀或讀寫方式打開的文件上讀取字符。其原型為:intfgetc(FILE*stream);其中,stream是由函數(shù)fopen()返回的文件指針,該函數(shù)讀取一個字符,并將文件位置指針移至下一個字符。當(dāng)成功讀取字符時,函數(shù)返回該字符;當(dāng)文件位置指針達到文件末尾時,函數(shù)返回EOF(EndofFile)符號常量,其在頭文件<stdio.h>中定義為-1。假設(shè)C盤test.txt文件中包含一行內(nèi)容:”HelloWorld!”,以下案例演示了如何實用fgetc()函數(shù)讀取文件內(nèi)容:9.5.1
按字符讀取fgetc()函數(shù)【例9.2】fgetc()讀取文件內(nèi)容1 #include<stdio.h>2 3 intmain(){4 FILE*fp;5 intc;6 //打開test.txt文件7 fp=fopen("C:\\test.txt","r");8 if(fp==NULL){9 perror("文件打開失敗");10 return-1;11 }12 //以字符的方式讀取文件內(nèi)容,直到文件結(jié)束標(biāo)志EOF13 while((c=fgetc(fp))!=EOF){14 printf("%c",c);15 }16
17 fclose(fp);18
19 return0;20 }程序運行結(jié)果如下:HelloWorld!9.5.1
按字符讀取fgetc()函數(shù)fgetc()函數(shù)一次只讀取一個字符,優(yōu)勢是簡單易用,并且可以處理二進制文件。缺點是當(dāng)處理大文件時,讀取效率較低,并且當(dāng)文件中有換行符時,fgetc()不會自動處理,而是將換行符當(dāng)做普通字符讀取。9.5.2按字符串讀取fgets()函數(shù)除了fgetc()函數(shù)按字符讀取文件外,C語言還提供了fgets()函數(shù),它可以從指定的文件流中讀取一行,并將其存儲為字符串。其函數(shù)原型如下:char*fgets(char*str,intn,FILE*stream);如果讀取文件內(nèi)容成功,fgets()函數(shù)會返回一個指向讀取到的字符串的指針,如果發(fā)生了錯誤或是到達了文件尾部,則會返回空指針。該函數(shù)一共有三個形參:參數(shù)str是一個指向字符數(shù)組的指針,用于存儲讀取的行。參數(shù)n指定了str數(shù)組的大小,以避免緩沖區(qū)溢出。該函數(shù)讀取直到達到指定的n-1個字符、換行符或文件結(jié)束符為止,并在讀取的字符后添加NULL終止符。如果成功,它返回第一個參數(shù)str的值,如果到達文件結(jié)束位置或發(fā)生錯誤,則返回NULL。參數(shù)stream表示一個文件指針。9.5.2按字符串讀取fgets()函數(shù)下面將test.txt文件中的內(nèi)容替換為李白的《將進酒》,然后編寫以下案例:【例9.3】fgets()讀取文件內(nèi)容1 #include<stdio.h>2 intmain(){3 FILE*fp;4 charbuffer[100];5
6 //打開文件7 fp=fopen("C:\\test.txt","r");8 if(fp==NULL){9 perror("文件讀取錯誤!");10 return-1;11 }12 //從文件中讀取一行文本13 while(fgets(buffer,sizeof(buffer),fp)!=NULL){14 printf("%s",buffer);15 }16
17 //關(guān)閉文件18 fclose(fp);19
20 return0;21 }9.5.2按字符串讀取fgets()函數(shù)程序運行結(jié)果如下: 將進酒·君不見 李白·唐君不見,黃河之水天上來,奔流到海不復(fù)回。君不見,高堂明鏡悲白發(fā),朝如青絲暮成雪。人生得意須盡歡,莫使金樽空對月。天生我材必有用,千金散盡還復(fù)來。烹羊宰牛且為樂,會須一飲三百杯。岑夫子,丹丘生,將進酒,杯莫停。與君歌一曲,請君為我傾耳聽。鐘鼓饌玉不足貴,但愿長醉不愿醒。古來圣賢皆寂寞,惟有飲者留其名。陳王昔時宴平樂,斗酒十千恣歡謔。主人何為言少錢,徑須沽取對君酌。五花馬,千金裘,呼兒將出換美酒,與爾同銷萬古愁。9.5.2按字符串讀取fgets()函數(shù)相較于fgetc()函數(shù),fgets()函數(shù)在讀取大文本文件時更加方便,也更加的高效,因為它可以一次讀取一整行的文件內(nèi)容。由于fgets()函數(shù)在讀取一行文本時會將其存儲到緩沖區(qū)中,如果輸入行比緩沖區(qū)大,可能會導(dǎo)致緩沖區(qū)溢出,這時需要手動處理緩沖區(qū)溢出的問題。如果輸入行文本比緩沖區(qū)大且沒有換行符,fgets()將會讀取緩沖區(qū)大小的字符并停止,這可能導(dǎo)致數(shù)據(jù)截斷。9.5.3按格式讀取fscanf()函數(shù)除了以上的兩種讀取文本文件的方式外,C語言還提供了一種按照指定格式讀取文件的方式,即fscanf()函數(shù)。其函數(shù)原型為:intfscanf(FILE*stream,constchar*format,...);其中,第1個參數(shù)為文件指針,第2個參數(shù)為格式控制參數(shù),第3個參數(shù)為地址參數(shù)列表,后兩個參數(shù)和返回值與函數(shù)scanf()相同。fscanf函數(shù)類似于scanf函數(shù),但它從文件流中讀取輸入,而不是標(biāo)準(zhǔn)輸入。它根據(jù)指定的格式字符串解析文件中的數(shù)據(jù),并將其存儲在提供的參數(shù)中。fscanf按照格式字符串中的格式從文件中讀取數(shù)據(jù),并將其轉(zhuǎn)換為相應(yīng)的數(shù)據(jù)類型。成功讀取數(shù)據(jù)后,返回成功匹配和轉(zhuǎn)換的參數(shù)數(shù)量。如果到達文件結(jié)尾或遇到錯誤,則返回EOF。9.5.3按格式讀取fscanf()函數(shù)現(xiàn)在請創(chuàng)建一個名為students.txt的文本文件,文件內(nèi)容可以填入一些學(xué)生的姓名和年齡,例如:王小明20張美麗22劉偉華21陳雪嬌19李華東23趙秀芳209.5.3按格式讀取fscanf()函數(shù)接著我們通過fscanf()函數(shù)讀取students.txt中的學(xué)生信息:【例9.4】fscanf()函數(shù)格式化讀取學(xué)生信息1 #include<stdio.h>2 #defineMAX_STUDENTS100 3 structStudent{4 charname[50];5 intage;6 }; 7 intmain(){8 FILE*fp;9 structStudentstudents[MAX_STUDENTS];10 intnum_students=0;11 fp=fopen("C:\\students.txt","r");12 if(fp==NULL){13 perror("文件打開錯誤!");14 return-1;15 }16 //從文件中讀取學(xué)生信息17 while(fscanf(fp,"%s%d",students[num_students].name,18 &students[num_students].age)==2){19 num_students++;20 if(num_students>=MAX_STUDENTS){21 printf("超過最大學(xué)生數(shù).\n");22 break;}23 }9.5.3按格式讀取fscanf()函數(shù)24//打印讀取到的學(xué)生信息25 printf("讀取到的學(xué)生信息:\n");26 for(inti=0;i<num_students;i++){27 printf("Name:%s,Age:%d\n",students[i].name,students[i].age);28 }29 30 fclose(fp);31 return0;32 }程序運行結(jié)果如下:讀取到的學(xué)生信息:Name:王小明,Age:20Name:張美麗,Age:22Name:劉偉華,Age:21Name:陳雪嬌,Age:19Name:李華東,Age:23Name:趙秀芳,Age:209.5.3按格式讀取fscanf()函數(shù)使用函數(shù)fscanf()和fprintf()進行文件的格式化讀寫,操作方便,容易理解,但輸入時要將ASCⅡ字符轉(zhuǎn)換成二進制數(shù),輸出時又要將二進制數(shù)轉(zhuǎn)換為ASCⅡ字符,耗時較多。總體而言,這些文件讀取函數(shù)在C語言中提供了靈活的方式來處理文件輸入??梢愿鶕?jù)實際需求選擇合適的函數(shù),以有效地讀取和處理文件中的數(shù)據(jù)。9.6 寫入文本文件目前我們已經(jīng)學(xué)會了如何讀取文本文件,但僅僅掌握讀取文件內(nèi)容的方法還遠遠不夠?,F(xiàn)在我們將開始學(xué)習(xí)文件的寫入方法。和文件的讀取一樣,文件的寫入方式也分為文本文件的寫入和二進制文件的寫入。在本節(jié)中,我們將介紹三種寫入文本文件的方法:使用fputc()函數(shù)按字符寫入、使用fputs()函數(shù)按字符串寫入以及使用fprintf()函數(shù)按格式化的方式寫入。9.6.1按字符寫入fputc()函數(shù)fputc()函數(shù)可以將單個字符寫入到指定的文件流中,其函數(shù)原型為:intfputc(intcharacter,FILE*stream);該函數(shù)有兩個形參:character表示想要寫入的字符,stream表示需要寫入的文件流。返回值為寫入文件的字符或EOF。通過下面的案例來演示通過fputs()函數(shù)將”HelloWorld!”字符串寫入到output.txt文件中。9.6.1按字符寫入fputc()函數(shù)【例9.5】fputc()寫入字符串至文件1 #include<stdio.h>2 intmain(){3 FILE*filePointer;4 chartext[]="HelloWorld";5 inti;6 //以寫入模式打開文件7 filePointer=fopen("output.txt","w");8 //檢查文件是否成功打開9 if(filePointer==NULL){10 printf("無法打開文件.\n");11 return-1;12 }13 //將字符串寫入文件14 for(i=0;text[i]!='\0';i++){15 fputc(text[i],filePointer);16 }17 printf("成功寫入文件.\n");18 //關(guān)閉文件19 fclose(filePointer);20 return0;21 }9.6.1按字符寫入fputc()函數(shù)在這個程序中,我們以"w"的方式打開文件。如果程序成功運行,并且在源文件所在的目錄下不存在output.txt文件,那么該程序?qū)?chuàng)建一個名為output.txt的文件,并將"HelloWorld!"寫入其中。如果已經(jīng)存在output.txt文件,程序?qū)⒄4蜷_該文件,并將"HelloWorld!"寫入其中。需要注意的是,如果多次運行該程序,output.txt文件中的內(nèi)容會始終只有一行”HelloWorld!”,因為以”w”的方式打開文件并寫入文本內(nèi)容時,會首先將原來文件中的內(nèi)容清空后再重新寫入,基于這樣的特性,我們可以通過這種方式達到清除某個文件內(nèi)容的目的,有興趣的讀者可以嘗試一下!fputc()函數(shù)的好處在于它允許逐字符地寫入文件,這意味著你可以更精確地控制寫入的內(nèi)容,包括特殊字符或者二進制數(shù)據(jù)。并且它適用于處理各種不同的數(shù)據(jù)類型,例如整數(shù)、字符等。由于需要逐字符寫入文件,當(dāng)需要寫入大量數(shù)據(jù)時,效率可能較低,因為它會頻繁地進行文件I/O操作。當(dāng)需要寫入大量文本時,使用fputc會使代碼變得冗長和繁瑣。9.6.2按字符串寫入fputs()函數(shù)C語言中,還提供了一種可以將一個字符串寫入指定文件流中的方法fputs(),其函數(shù)原型為:intfputs(constchar*str,FILE*stream);fputs函數(shù)它接受一個指向字符串的指針和一個指向文件的指針作為參數(shù),并返回非負值表示成功,或EOF表示失敗。下面的案例將演示如何通過fputs()函數(shù)將”HelloWorld!”字符串寫入到output2.txt文件中。9.6.2按字符串寫入fputs()函數(shù)【例9.6】fputs()寫入字符串至文件1 #include<stdio.h>2 intmain(){3 FILE*filePointer;4 chartext[]="HelloWorld!";5 //打開文件以寫入模式6 filePointer=fopen("output2.txt","w");7 //檢查文件是否成功打開8 if(filePointer==NULL){9 printf("無法打開文件.\n");10 return-1;11 }12 //將字符串寫入文件13 if(fputs(text,filePointer)==EOF){14 printf("寫入文件時發(fā)生錯誤.\n");15 return-1;16 }17
18 printf("成功寫入文件.\n");19
20 //關(guān)閉文件21 fclose(filePointer);22
23 return0;24 }9.6.2按字符串寫入fputs()函數(shù)同例9.6類似,當(dāng)程序運行成功時,會在源碼文件所處的文件路徑下創(chuàng)建一個名為output2.txt的文件,文件內(nèi)容為”HelloWorld!”。本案例的不同點在于寫入文件的方式不同。fputs函數(shù)可以一次寫入一個字符串,使得代碼更加簡潔明了,由于一次性寫入整個字符串,fputs在處理大量文本時通常比fputc效率更高。但fputs函數(shù)只能寫入字符串,如果你需要控制寫入的內(nèi)容,或者寫入特殊字符或二進制數(shù)據(jù),可能就不那么方便了。fputs函數(shù)會在碰到NULL結(jié)尾字符\0時停止寫入,因此如果要寫入的字符串包含NULL字符,則可能會截斷寫入過程。9.6.3按格式化方式寫入fprintf()函數(shù)除了以上兩種寫入文本文件的方法外,C語言還提供了一種可以將格式化數(shù)據(jù)輸出到指定文件流中的方法fprintf()。其函數(shù)原型為:intfprintf(FILE*stream,constchar*format,...);其中,stream參數(shù)是指向要寫入的文件流的指針,format參數(shù)是一個格式控制字符串,它包含了待寫入內(nèi)容的格式以及需要替換的變量,其余的參數(shù)是需要根據(jù)格式字符串進行替換的數(shù)據(jù)。fprintf()函數(shù)與printf()函數(shù)非常類似,但fprintf()不是將輸出發(fā)送到標(biāo)準(zhǔn)輸出流(通常是顯示器),而是將其發(fā)送到指定的文件流中。這使得fprintf()函數(shù)非常靈活,可以用于將輸出寫入文件、網(wǎng)絡(luò)連接或其他輸出設(shè)備。9.6.3按格式化方式寫入fprintf()函數(shù)通過以下案例,將《HarryPotter》這本書的信息寫入文件?!纠?.7】fprintf()函數(shù)寫入書籍信息1 #include<stdio.h>2 typedefstruct{3 chartitle[100];4 charauthor[100];5 intyear;6 floatprice;7 }Book;8 intmain(){9 FILE*fp;10 Bookbook; 11 //打開一個名為books.txt的文件,準(zhǔn)備寫入12 fp=fopen("books.txt","w");13 if(fp==NULL){14 printf("Erroropeningfile.\n");15 return1;16 }17 //輸入圖書信息18 printf("Enterbooktitle:");19 scanf("%s",book.title);20 printf("Enterbookauthor:");21 scanf("%s",book.author);22 printf("Enterpublicationyear:");23 scanf("%d",&book.year);24 printf("Enterprice:");25 scanf("%f",&book.price);9.6.3按格式化方式寫入fprintf()函數(shù)26 //將圖書信息寫入文件流中27 fprintf(fp,"Title:%s\n",book.title);28 fprintf(fp,"Author:%s\n",book.author);29 fprintf(fp,"Year:%d\n",book.year);30 fprintf(fp,"Price:%.2f\n",book.price); 31 //關(guān)閉文件32 fclose(fp);33
34 printf("書籍信息以寫入至books.txt.\n");35 return0;36 }程序運行后并按照提示輸入以下內(nèi)容:Enterbooktitle:HarryPotterEnterbookauthor:JK_RowlinEnterpublicationyear:1997Enterprice:98程序會將輸入信息寫入文件流。程序運行結(jié)束后,我們會在源碼文件所在的文件路徑下看到新創(chuàng)建的一個名為books.txt的文件,文件內(nèi)容為:Title:HarryPotterAuthor:JK_RowlinYear:1997Price:98.009.6.3按格式化方式寫入fprintf()函數(shù)fpintf()函數(shù)可以以格式化的方式輸出數(shù)據(jù)到文件中,可以使用格式控制字符串來指定輸出格式,使得輸出更加靈活、可讀性更高,并且可以輸出各種不同類型的數(shù)據(jù),包括整數(shù)、浮點數(shù)、字符、字符串等,而且無需考慮數(shù)據(jù)類型轉(zhuǎn)換的問題。但需要對格式化字符串進行解析和處理,相較于fputc()和fputs(),fprintf()函數(shù)可能會稍微降低一些性能。綜上所述,C語言提供了豐富的寫入文本文件的函數(shù)和方法,選擇使用哪個函數(shù)取決于具體的需求。如果需要進行格式化輸出或者輸出復(fù)雜的數(shù)據(jù)類型,可以選擇fprintf();如果只需簡單地輸出字符或字符串,可以使用fputc()或fputs(),具體根據(jù)情況進行選擇。9.7 文本文件操作案例現(xiàn)在我們已經(jīng)熟悉了C語言中常用的文本操作函數(shù),接下來我們將通過下面幾個案例來進一步加深對文本操作函數(shù)的理解。9.7.1文本文件復(fù)制文件的復(fù)制是計算機操作系統(tǒng)的基礎(chǔ)功能之一。下面我們結(jié)合前面學(xué)習(xí)到的文件操作函數(shù),編寫一個程序來實現(xiàn)文件的復(fù)制操作。圖9-1展示了案例9.8的實現(xiàn)邏輯圖9-1復(fù)制操作流程圖9.7.1文本文件復(fù)制首先,我們使用fopen()函數(shù)分別以只讀("r")和只寫("w")方式打開待復(fù)制文件和待寫入目標(biāo)文件,并創(chuàng)建兩個文件指針source_file和destination_file。接下來,我們通過source_file文件指針使用fgets()函數(shù)逐行讀取待復(fù)制文件中的內(nèi)容。每讀取一行,就使用destination_file文件指針和fputs()函數(shù)將讀取到的內(nèi)容寫入目標(biāo)文件。當(dāng)所有內(nèi)容都被讀取和寫入后,我們分別關(guān)閉source_file和destination_file文件指針。這樣,我們就完成了文件的復(fù)制操作。以下是實現(xiàn)案例的代碼:9.7.1文本文件復(fù)制【例9.8】文件的復(fù)制1 #include<stdio.h>2 #include<stdlib.h> 3 #defineBUFFER_SIZE1024 4 intmain(){5 FILE*source_file,*destination_file;6 charsource_filename[]="source.txt";//源文件名7 chardestination_filename[]="destination.txt";//目標(biāo)文件名8 charbuffer[BUFFER_SIZE]; 9 //打開源文件進行讀取10 source_file=fopen(source_filename,"r");11 if(source_file==NULL){12 perror("打開源文件失敗.");13 returnEXIT_FAILURE;14 } 15 //創(chuàng)建目標(biāo)文件進行寫入16 destination_file=fopen(destination_filename,"w");17 if(destination_file==NULL){18 perror("創(chuàng)建目標(biāo)文件失敗.");19 fclose(source_file);20 returnEXIT_FAILURE;21 }22 //逐行讀取源文件并寫入目標(biāo)文件,直到源文件結(jié)束23 while(fgets(buffer,BUFFER_SIZE,source_file)!=NULL){24 fputs(buffer,destination_file);25 }9.7.1文本文件復(fù)制26 //關(guān)閉文件27 fclose(source_file);28 fclose(destination_file);29
30 printf("文件復(fù)制成功!\n");31
32 returnEXIT_SUCCESS;33 }程序成功運行后,會得到一個與源文件文件內(nèi)容相同的目標(biāo)文件。這樣就通過對fopen()、fclose()、fgets()和fputs()函數(shù)的簡單綜合運用,實現(xiàn)了文件的復(fù)制功能。9.7.2文本文件統(tǒng)計除了用文件操作函數(shù)完成文件的復(fù)制功能外,還可以通過文件操作函數(shù)完成對某個文件中英文單詞數(shù)的統(tǒng)計。我們還是先通過圖9-2來理解英文單詞統(tǒng)計的實現(xiàn)邏輯:如圖9-2,首先,我們需要定義兩個變量,word_count用于統(tǒng)計單詞數(shù),in_word用于判斷當(dāng)前字符是否還在一個單詞中,并將它們的值初始化為0。接下來,我們打開一個待統(tǒng)計的文件,我們使用fgetc()函數(shù)讀取文件內(nèi)容。如果讀取成功,我們需要對所讀取的字符進行判斷。如果該字符是一個字母,并且in_word的值為0,那么我們將word_count加1,并將in_word設(shè)置為1;如果該字符不是一個字母,我們直接將in_word設(shè)置為0。接著讀取下一個字符。我們重復(fù)以上步驟,直到文件的所有內(nèi)容都被讀取完畢。這樣,我們就完成了對文件中單詞數(shù)的統(tǒng)計。圖9-2英文單詞統(tǒng)計流程圖9.7.2文本文件統(tǒng)計在進行實現(xiàn)之前,先創(chuàng)建一個名為TheOldManAndSea.txt的文件,并將以下內(nèi)容寫入文件:Thesunrosethinlyfromtheseaandtheoldmancouldseetheotherboats,lowonthewaterandwellintowardtheshore,spreadoutacrossthecurrent.Thenthesunwasbrighterandtheglarecameonthewaterandthen,asitroseclear,theflatseasentitbackathiseyessothatithurtsharplyandherowedwithoutlookingintoit.Helookeddownintothewaterandwatchedthelinesthatwentstraightdownintothedarkofthewater.Hekeptthemstraighterthananyonedid,sothatateachlevelinthedarknessofthestreamtherewouldbeabaitwaitingexactlywherehewishedittobeforanyfishthatswamthere.Othersletthemdriftwiththecurrentandsometimestheywereatsixtyfathomswhenthefishermenthoughttheywereatahundred.9.7.1文本文件復(fù)制例9.9是案例的實現(xiàn)源碼:
【例9.10】統(tǒng)計文本文件單詞數(shù)1 #include<stdio.h>2 #include<ctype.h>3 intmain(){4 FILE*file;//聲明文件指針5 charfilename[]="TheOldManAndSea.txt";//文件路徑6 charch;//用于存儲讀取的字符7 intword_count=0;//單詞計數(shù)器8 intin_word=0;//標(biāo)志位,指示當(dāng)前是否在單詞中9 //嘗試打開文件10 file=fopen(filename,"r");11 if(file==NULL){//檢查文件是否成功打開12 printf("文件:%s打開失敗.\n",filename);13 return1;//如果打開失敗,則退出程序14 //逐個字符讀取文件內(nèi)容,直到文件末尾15 while((ch=fgetc(file))!=EOF){16 if(isalpha(ch)){//如果當(dāng)前字符是字母17 if(!in_word){//如果當(dāng)前不在單詞中18 word_count++;//增加單詞計數(shù)19 in_word=1;//設(shè)置標(biāo)志位,表示當(dāng)前在單詞中20 }21 }else{22 in_word=0;//如果當(dāng)前字符不是字母,設(shè)置標(biāo)志位為0,表示不在單詞中23 }24 }9.7.1文本文件復(fù)制25 fclose(file);//關(guān)閉文件 26 //輸出單詞數(shù)27 printf("文件%s的單詞數(shù)為:%d\n",filename,word_count); 28 return0;29 }程序運行結(jié)果如下:文件TheOldManAndSea.txt的單詞數(shù)為:150該案例只需要通過fgetc()函數(shù)逐步讀取文本中各個字符,并進行判斷,就能完成整個文件的單詞數(shù)的統(tǒng)計。9.8寫入二進制文件9.8.1fwrite()函數(shù)fwrite()函數(shù)是用于向文件中寫入數(shù)據(jù)的標(biāo)準(zhǔn)庫函數(shù)之一,其作用是將數(shù)據(jù)塊以二進制形式寫入文件。這個函數(shù)在文件I/O操作中扮演著重要的角色。其函數(shù)原型為:size_tfwrite(constvoid*ptr,size_tsize,size_tnmemb,FILE*stream);fwrite()函數(shù)的主要功能是將內(nèi)存文件塊buffer寫入到指定的文件流中。該函數(shù)有4個形參,其參數(shù)含義和fread()函數(shù)類似:ptr指向要寫入的數(shù)據(jù)塊的起始地址;size表示每個數(shù)據(jù)項的大小,以字節(jié)為單位,即要寫入的每個數(shù)據(jù)項的字節(jié)數(shù);nmemb表示寫入的數(shù)據(jù)項的數(shù)量,或者說是要寫入幾次數(shù)據(jù)塊;stream表示要寫入的文件指針。fwrite()函數(shù)會從指針ptr指向的內(nèi)存位置開始,按照給定的size和nmemb參數(shù),將數(shù)據(jù)寫入到由stream指向的文件中。函數(shù)返回成功寫入的數(shù)據(jù)項數(shù)量,如果發(fā)生錯誤則返回0。要注意的是,fwrite()函數(shù)是以二進制形式寫入數(shù)據(jù)的,因此不會對數(shù)據(jù)進行任何格式化操作。根據(jù)寫入文件的方式,一般分為順序?qū)懭牒碗S機寫入,以下是對這兩種文件寫入方式的詳細介紹。9.8.2二進制文件的順序?qū)懭腠樞驅(qū)懭胧侵赋绦虬凑瘴募?dāng)前位置開始,連續(xù)地向文件寫入數(shù)據(jù)。當(dāng)你使用模式如"wb"或"ab"打開一個文件并使用如fwrite()函數(shù)進行數(shù)據(jù)寫入時,數(shù)據(jù)會被添加到文件的末尾。每次寫入后,文件的寫入位置自動更新,為下一次寫入做準(zhǔn)備。如果文件已經(jīng)存在并且使用"wb"模式打開,原有內(nèi)容會被覆蓋,文件從頭開始寫入;如果希望在文件末尾追加數(shù)據(jù),則應(yīng)使用"ab"模式。順序?qū)懭氲奶攸c是靈活性高,能夠精準(zhǔn)控制數(shù)據(jù)寫入的位置。適用于需要更新文件特定部分的場景,如數(shù)據(jù)庫、配置文件編輯等。下面的案例將演示如何將一段文字以二進制的方式順序?qū)懭胛募?.8.2二進制文件的順序?qū)懭搿?.10】二進制的方式順序?qū)懭胛募? #include<stdio.h>2 #include<stdlib.h>3 intmain(){4 FILE*file;5 chardata[]="Hello,world!\nThisisatestfile."; 6 //寫入數(shù)據(jù)到文件7 file=fopen("fwrite_test.bin","wb");//以二進制寫入模式打開文件8 if(file==NULL){9 perror("文件打開錯誤");10 returnEXIT_FAILURE;11 }12 //使用fwrite()將數(shù)據(jù)寫入文件13 size_tbytes_written=fwrite(data,sizeof(char),sizeof(data),file);14 if(bytes_written!=sizeof(data)){15 perror("文件寫入錯誤");16 returnEXIT_FAILURE;17 }18 fclose(file);19 printf("數(shù)據(jù)已成功寫入到文件!\n");20 returnEXIT_SUCCESS;21 }程序運行成功后,將在程序所在文件夾中創(chuàng)建一個名為fwrite_test.bin的二進制文件,由于文件中的內(nèi)容是以二進制方式寫入的,所以無法通過簡單的方式解讀其內(nèi)容。9.8.3二進制文件的隨機寫入隨機寫入方式允許程序向指定文件中的確切位置寫入數(shù)據(jù),而不是僅僅在文件末尾追加。這通常需要先使用fseek或lseek函數(shù)將文件指針按照偏移量定位到期望的位置,然后再執(zhí)行寫入操作(如使用fwrite函數(shù))。通過這種方式,你可以修改文件中已存在的數(shù)據(jù)或在文件中的任意位置插入數(shù)據(jù)。其特點是提供高度的靈活性,能夠精準(zhǔn)控制數(shù)據(jù)寫入的位置。適用于需要更新文件特定部分的場景,如數(shù)據(jù)庫、配置文件編輯等操作。想要實現(xiàn)二進制文件的隨機寫入,需要介紹一下fseek()函數(shù)。Fseek()是C語言標(biāo)準(zhǔn)庫中的一個函數(shù),用于在文件中移動讀取或?qū)懭胛恢玫闹羔?。這個功能對于實現(xiàn)隨機訪問文件中的特定位置數(shù)據(jù)至關(guān)重要。下面是對fseek()函數(shù)的詳細介紹:9.8.3二進制文件的隨機寫入函數(shù)原型:intfseek(FILE*stream,longintoffset,intwhence);其中stream:是指向FILE結(jié)構(gòu)體的指針,該結(jié)構(gòu)體由fopen函數(shù)打開文件時返回,代表了待操作的文件。offset:是一個長整型數(shù)值,表示相對于whence參數(shù)指定的位置移動的字節(jié)數(shù)。正數(shù)表示向前移動(向文件末尾方向),負數(shù)表示向后移動(向文件開頭方向)。whence:是一個整型常量,決定了偏移量offset的計算基準(zhǔn)。它可以取以下三個值之一:SEEK_SET:將偏移量設(shè)置為文件開頭的位置。如果offset為0,則會將文件位置指針移到文件的開頭。SEEK_CUR:將偏移量設(shè)置為當(dāng)前文件位置。如果offset為0,則文件位置不會改變。SEEK_END:將偏移量設(shè)置為文件結(jié)尾的位置。注意,此時offset若為正數(shù),則實際上會將指針置于文件結(jié)束標(biāo)志之后,這對于在文件末尾追加數(shù)據(jù)可能有用;若為負數(shù),則會將指針移至距離文件末尾相應(yīng)數(shù)值的字節(jié)位置。9.8.3二進制文件的隨機寫入下面的案例將演示如何將一段文字以二進制的方式隨機寫入文件:【9.11】二進制的方式隨機寫入文件1 #include<stdio.h2 intmain(){3 FILE*file;4 chardata[]="Hello,world!\nThisisatestfile."; 5 //打開文件用于寫入6 file=fopen("fwrite_test_random.bin","wb");//二進制寫模式7 if(file==NULL){8 perror("無法打開文件");9 return1;10 }11 //定位文件指針到特定位置12 fseek(file,100,SEEK_SET);//將文件指針移動到文件的第100個字節(jié)13 //寫入數(shù)據(jù)到文件14 fwrite(data,sizeof(char),1,file);15
16 //關(guān)閉文件17 fclose(file);18
19 return0;20 }9.9 讀取二進制文件9.9.1fread()函數(shù)在計算機中,除了文本文件外,還存在大量的二進制文件,二進制文件一般是不可視的,需要通過特定的軟件才能打開,例如mp3音樂文件、mp4視頻文件、jpg圖片文件和bin二進制文件等。這類文件C語言提供了可以讀取的函數(shù)fread(),fread()與前面讀取文本文件的方法不同,它一次會讀取一組數(shù)據(jù),或是稱做一塊數(shù)據(jù)。fread()的函數(shù)原型為:size_tfread(void*ptr,size_tsize,size_tnmemb,FILE*stream);該函數(shù)一共有4個形參。正如前面所描述到的,fread()一次可以讀取一塊數(shù)據(jù),因此,在使用fread()函數(shù)之前,一般會定義一個數(shù)據(jù)塊buffer。prt是一個指針,指向要存放讀取數(shù)據(jù)的數(shù)據(jù)塊的起始地址;在定義數(shù)據(jù)塊時,一般會定義一定長度的某數(shù)據(jù)類型的數(shù)據(jù)塊,size代表的是數(shù)據(jù)塊中每個元素的所占字節(jié)數(shù);nmemb表示一次要讀取的數(shù)據(jù)塊的數(shù)量;stream表示FILE對象指針。文件根據(jù)讀取方式,一般分為順序讀取和隨機讀取,以下是這兩種文件寫入方式的詳細介紹。9.9 讀取二進制文件9.9.1fread()函數(shù)程序運行結(jié)果如下:已讀取760字節(jié):Thesunrosethinlyfromtheseaandtheoldmancouldseetheotherboats,lowonthewaterandwellintowardtheshore,spreadoutacrossthecurrent.Thenthesunwasbrighterandtheglarecameonthewaterandthen,asitroseclear,theflatseasentitbackathiseyessothatithurtsharplyandherowedwithoutlookingintoit.Helookeddownintothewaterandwatchedthelinesthatwentstraightdownintothedarkofthewater.Hekeptthemstraighterthananyonedid,sothatateachlevelinthedarknessofthestreamtherewouldbeabaitwaitingexactlywherehewishedittobeforanyfishthatswamthere.Othersletthemdriftwiththecurrentandsometimestheywereatsixtyfathomswhenthefishermenthoughttheywereatahundred.該程序還有不完善的地方:由于fread()采取的是二進制的方式讀取文件,所讀取的是二進制數(shù)據(jù),而printf()函數(shù)通常用于格式化的字符串輸出,所以該程序在實際運行的過程中可能輸出的結(jié)果不那么理想。對于二進制數(shù)據(jù)的輸出,一般會采用fprintf()函數(shù)進行輸出,其效果表現(xiàn)會更好,也更加規(guī)范,該方法的使用將在后面的內(nèi)容中介紹。9.9.2二進制文件的順序讀取順序讀取是指按照文件中數(shù)據(jù)的物理排列順序,從頭到尾依次讀取文件中的內(nèi)容。當(dāng)你打開一個文件用于讀取時,默認就是以順序讀取的方式進行操作。每進行一次讀取操作,文件指針會自動向后移動,指向下一個待讀取的數(shù)據(jù)塊。這種方式適用于需要處理文件中所有數(shù)據(jù)或大部分?jǐn)?shù)據(jù)的場景。其特點是簡單易用,不需要特別設(shè)置讀取位置。適合于讀取連續(xù)、大量且不需要跳躍訪問的數(shù)據(jù)。順序讀取效率較高,特別是在磁盤I/O操作上,因為減少了定位文件指針的需求。下面使用例9.11生成的”fwrite_test.bin”二進制文件,通過fread()函數(shù)實現(xiàn)二進制文件的順序讀取。9.9.2二進制文件的順序讀取【例9.12】順序讀取二進制文件1 #include<stdio.h>2 intmain(){3 FILE*fp;4 charbuffer[1024];5 size_tbytes_read; 6 //打開文件7 fp=fopen("fwrite_test.bin","rb");//以二進制模式打開文件8 if(fp==NULL){9 perror("文件打開錯誤.");10 return1;11 }12 //使用fread()讀取文件數(shù)據(jù)13 bytes_read=fread(buffer,sizeof(char),1024,fp);14 if(bytes_read==0){15 if(feof(fp)){16 printf("已經(jīng)到達文件末尾.\n");17 }else{18 perror("文件讀取錯誤");19 }20 }else{21 printf("已讀取%zu字節(jié):%s\n",bytes_read,buffer);}22 //關(guān)閉文件23 fclose(fp);24 return0;}9.9.3二進制文件的隨機讀取隨機讀取方式允許程序直接跳轉(zhuǎn)到文件中的任意位置進行讀取操作,無需按順序從頭開始。這種方式通過指定一個偏移量和一個起始基準(zhǔn)點(文件開頭、當(dāng)前位置或文件末尾),可以靈活地訪問文件中任意部分的數(shù)據(jù)。其特點是提供了靈活性,可以快速訪問文件中任何位置的數(shù)據(jù)。適用于需要訪問文件中特定位置數(shù)據(jù)或頻繁在文件中跳轉(zhuǎn)的場景。下面使用例9.12生成的”fwrite_tes_randomt.bin”二進制文件,通過調(diào)用fread()函數(shù)實現(xiàn)二進制文件的隨機讀取。9.9.3二進制文件的隨機讀取【例9.13】隨機讀取二進制文件1 #include<stdio.h>2 intmain(){3 FILE*file;4 chardata[50];//假設(shè)文件中最多包含50個字節(jié)的數(shù)據(jù)5 //打開文件用于讀取6 file=fopen("fwrite_test_random.bin","rb");//二進制讀模式7 if(file==NULL){8 perror("無法打開文件");9 return1;10 }11 //將文件指針移動到文件的第100個字節(jié)處12 fseek(file,100,SEEK_SET);13 //從文件中讀取數(shù)據(jù)14 size_tbytes_read=fread(data,sizeof(char),sizeof(data),file);15 if(bytes_read==0){16 perror("讀取文件錯誤");17 fclose(file);18 return1;19 }20 //輸出讀取的數(shù)據(jù)21 printf("從文件中讀取的數(shù)據(jù)為:\n%s\n",data);22 //關(guān)閉文件23 fclose(file);24 return
溫馨提示
- 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)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 石渣填筑施工工藝及安全方案
- 企業(yè)客戶服務(wù)標(biāo)準(zhǔn)操作手冊范本
- 管道拆除方案
- 物流運輸安全教育投資計劃
- 生鮮電商行業(yè)運營模式探討報告
- 湖南母嬰行業(yè)分析報告
- 南天控股行業(yè)地位分析報告
- 社區(qū)店的行業(yè)分析報告
- 航拍市場行業(yè)需求分析報告
- 服裝租賃行業(yè)數(shù)據(jù)分析報告
- 2025年專利管理與保護操作手冊
- 2025云南山海遊旅游集團有限公司招聘10人考試備考題庫及答案解析
- 2025年人工智能(AI)訓(xùn)練師專業(yè)知識考試題庫(完整版)
- 【全文翻譯】歐盟-GMP-附錄1《無菌藥品生產(chǎn)》智新版
- 2025年公務(wù)員(省考)測試卷附答案詳解
- 2025年醫(yī)療統(tǒng)計師崗位招聘面試參考題庫及參考答案
- 2025年湖南邵陽經(jīng)開貿(mào)易投資有限公司招聘12人筆試考試參考試題及答案解析
- 白內(nèi)障手術(shù)術(shù)前準(zhǔn)備和術(shù)后護理流程
- 多動癥兒童在感統(tǒng)訓(xùn)練
- 環(huán)保生產(chǎn)應(yīng)急預(yù)案
- 殯葬禮儀服務(wù)創(chuàng)新創(chuàng)業(yè)項目商業(yè)計劃書
評論
0/150
提交評論