《C語言程序設計新視角》課件第8章_第1頁
《C語言程序設計新視角》課件第8章_第2頁
《C語言程序設計新視角》課件第8章_第3頁
《C語言程序設計新視角》課件第8章_第4頁
《C語言程序設計新視角》課件第8章_第5頁
已閱讀5頁,還剩110頁未讀, 繼續(xù)免費閱讀

下載本文檔

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

文檔簡介

第8章文件8.1問題的引入 8.2文件的概念 8.3內(nèi)存和外存的數(shù)據(jù)交流8.4程序如何操作文件8.5關于文件讀寫的討論8.6程序調試與數(shù)據(jù)測試文件8.7本章小結

【主要內(nèi)容】

?文件的概念;

?通過人工操作文件與程序操作文件的對比,說明文件操作的基本步驟;

?文件操作庫函數(shù)的介紹及使用方法實例;

?分類簡要介紹可以對文件進行操作的庫函數(shù)功能。

【學習目標】

?能夠創(chuàng)建、讀取、寫入、更新文件;

?熟悉順序訪問文件處理;

?熟悉隨機訪問文件處理。

編程的目的是對數(shù)據(jù)進行處理,完成特定的功能。數(shù)據(jù)的處理包括數(shù)據(jù)的輸入、加工處理及結果的輸出。對程序的運行及測試涉及數(shù)據(jù)的輸入/輸出。數(shù)據(jù)的輸入/輸出有如下特點:8.1問?題?的?引?入

(1)待處理的數(shù)據(jù)由程序員編程時在程序中設定(該程序只能處理固定的數(shù)據(jù))或在程序運行時由用戶輸入(每次運行時都要重新輸入)。

(2)程序處理的結果輸出到顯示屏,無法實現(xiàn)永久性的保存。

當處理的數(shù)據(jù)有下列情形出現(xiàn)時,可把這些數(shù)據(jù)保存起來,以達到查看方便或可以反復使用的目的。

(1)輸入:輸入的數(shù)據(jù)量很大;輸入的數(shù)據(jù)每次都相同。

(2)輸出:需要多次查看程序結果;程序結果較多,一屏顯示不下。計算機系統(tǒng)長久保存數(shù)據(jù)的方法是把數(shù)據(jù)存儲到外存上,操作系統(tǒng)以文件為單位對外存的數(shù)據(jù)進行管理。

文件:存儲在外部介質上具有名稱(文件名)的一組相關數(shù)據(jù)的集合。

文件是一組相關數(shù)據(jù)的有序集合,這個數(shù)據(jù)集有一個名稱,叫做文件名。實際上在前面的各章中我們已經(jīng)多次使用了文件,例如源程序文件、目標文件、可執(zhí)行文件、庫文件(頭文件)等。用文件可長期保存數(shù)據(jù),并實現(xiàn)數(shù)據(jù)共享。8.2文?件?的?概?念在C語言中按內(nèi)容存放方式,文件可分為二進制文件和文本文件兩種。

1.二進制文件

二進制文件是按二進制的編碼方式來存放數(shù)據(jù)的。例如,整數(shù)5678的存儲形式為0001011000101110,只占兩個字節(jié)(5678的十六進制為0x162E)。

二進制文件雖然也可在屏幕上顯示,但其內(nèi)容無法讀懂。

2.文本文件

文本文件也稱為ASCII碼文件,這種文件在磁盤中存放時每個字符對應一個字節(jié),用于存放對應的ASCII碼。例如,數(shù)5678的存儲形式如表8.1所示。

表8.1文本文件中的字符表示

ASCII碼文件可在屏幕上按字符顯示。例如源程序文件就是ASCII碼文件,由于是按字符顯示,因此我們能讀懂文件內(nèi)容。

文本文件與二進制文件的區(qū)別:將文件看做是由一個一個字符組成的,一個字符為一個單位;而二進制文件則是由bit(位)組成的,一個bit為一個單位。

流式文件:C語言將文件看做“數(shù)據(jù)流”,即文件是由一串連續(xù)的、無間隔的字節(jié)構

成,用文件結束符結束,這種結構稱為“流式文件結構”。

流式文件在處理時不需考慮文件中數(shù)據(jù)的性質、類型和存放格式,訪問時只是以字節(jié)為單位對數(shù)據(jù)進行存取,而將對數(shù)據(jù)結構的分析、處理等工作都交給后續(xù)程序去完成。因此,這樣的文件結構更具靈活性,對存儲空間的利用率高。

文件結束標志有以下兩種:

(1)EOF——文本文件結束標志。EOF是EndofFile的縮寫,整型符號常量,在<stdio.h>頭文件中定義,它的值通常是-1。

(2)feof函數(shù)——用來判斷文件是否結束。二進制文件與文本文件均適用。

關于EOF

在程序中測試符號常量EOF,而不是測試-1,這可以使程序更具有可移植性。ANSI標準強調,EOF是負的整型值(但沒有必要一定是-1)。因此,在不同的系統(tǒng)中,EOF可能具有不同的值,即輸入EOF的按鍵組合取決于系統(tǒng),如下表所示。

緩沖文件系統(tǒng)

由于CPU與內(nèi)存的工作速度非???,而對外存(磁盤、光盤等)的存取速度很慢,當訪問外存時,主機必須等待慢速的外存操作完成后才能繼續(xù)工作,嚴重影響了CPU效率的發(fā)揮。解決二者速度不匹配的方法是采用“緩沖區(qū)”技術。

緩沖讀寫操作可使磁盤得到高效利用。標準C采用緩沖文件系統(tǒng),如圖8.1所示。8.3內(nèi)存和外存的數(shù)據(jù)交流

圖8.1緩沖文件系統(tǒng)

緩沖區(qū)是在內(nèi)存中分配的一塊存儲空間,是由操作系統(tǒng)在每個文件被打開時自動建立并管理的。緩沖區(qū)的大小由C的具體版本確定,一般為512字節(jié)。

緩沖區(qū)的作用:當需要向外存文件中寫入數(shù)據(jù)時,并不是每次都直接寫入外存,而是先寫入到緩沖區(qū),只有當緩沖區(qū)的數(shù)據(jù)存滿或文件關閉時,才自動將緩沖區(qū)的數(shù)據(jù)一次性寫入外存。讀數(shù)時,也是一次將一個數(shù)據(jù)塊讀入緩沖區(qū)中,以后讀取數(shù)據(jù)時,先到緩沖區(qū)中尋找,若找到,則直接讀出,否則,再到外存中尋找,找到后將其所在的數(shù)據(jù)塊一次讀入緩沖區(qū)。緩沖區(qū)可有效減少訪問外存的次數(shù)。

使用緩沖文件系統(tǒng)時,系統(tǒng)將自動為每一個打開的文件建立緩沖區(qū),此后,程序對文件的讀寫操作實際上是對文件緩沖區(qū)的操作。

為了便于編程,ANSIC將有關文件緩沖區(qū)的一些信息(如緩沖區(qū)對應的文件名、文件所允許的操作方式、緩沖區(qū)的大小以及當前讀寫數(shù)據(jù)在緩沖區(qū)的位置等)用一個結構體類型來描述,類型名為FILE,該結構體類型的定義包含在stdio.h文件中。文件類型FILE描述文件緩沖區(qū)的信息,具體內(nèi)容為:

typedefstruct_iobuf

{

char*_ptr; //指向buffer中第一個未讀的字節(jié)

int_cnt; //記錄剩余未讀字節(jié)的個數(shù)

char*_base; //指向一個字符數(shù)組,即這個文件的緩沖區(qū)

int_flag; //標志位,記錄了FILE結構所代表的打開文件的一些屬性

int_file; //用于獲取文件描述,可使用fileno函數(shù)獲得此文件的句柄

int_charbuf; //單字節(jié)的緩沖,如果為單字節(jié)緩沖,_base將無效

int_bufsiz; //緩沖區(qū)大小

char*_tmpfname; //臨時文件名

}FILE;有了FILE類型后,每當打開一個文件時,操作系統(tǒng)自動為該文件建立一個FILE類型的結構體數(shù)據(jù),并返回指向它的指針,系統(tǒng)將被打開文件及緩沖區(qū)的各種信息都存入這個FILE型數(shù)據(jù)區(qū)域中,程序通過上述指針獲得文件信息及訪問文件,如圖8.2所示。

文件關閉后,它的文件結構體被釋放。

只要有了指向某個文件的文件指針,具體的文件操作都由系統(tǒng)提供的文件操作函數(shù)實現(xiàn),而不需了解文件緩沖區(qū)的具體情況,方便了程序員關于文件操作的編程。

圖8.2文件操作

文件通常是駐留在外部介質(如磁盤等)上的,在使用時才調入內(nèi)存中。

在文件的操作中,經(jīng)常會涉及文件的讀寫操作,通常把數(shù)據(jù)從磁盤流到內(nèi)存稱為“讀”,數(shù)據(jù)從內(nèi)存流到磁盤稱為“寫”。

每個文件由唯一的文件名來標識。計算機按文件名對文件進行讀、寫等有關操作。8.4程序如何操作文件對文件操作的經(jīng)驗是,如果想找存在外部介質上的數(shù)據(jù),必須先按文件名找到指定的文件,然后再從該文件中讀取數(shù)據(jù),文件使用完畢,再關閉它。那么用程序來對文件進行操作,是否也是這樣的步驟呢?具體又是怎么處理的呢?用程序來訪問文件,與我們直接對文件的操作與步驟是類似的。

程序訪問文件的三個步驟如下:

(1)打開文件。

(2)操作文件。

(3)關閉文件。程序對文件的操作步驟如下:

(1)在磁盤上建立、保存文件。

(2)打開已有文件。

(3)讀寫文件。

在C語言中,沒有輸入/輸出語句,對文件的讀寫都是用庫函數(shù)來實現(xiàn)的。ANSI規(guī)定了標準輸入/輸出函數(shù),用它們對文件進行讀寫,相應的庫函數(shù)參見附錄C。

廣義上,操作系統(tǒng)將每一個與主機相連的輸入/輸出設備都看做是文件,把它們的輸入/輸出等同于對磁盤文件的讀和寫。通常把顯示器定義為標準輸出文件,一般情況下在屏幕上顯示有關信息就是向標準輸出文件輸出。如前面經(jīng)常使用的printf、putchar函數(shù)就是這類輸出。

鍵盤通常被指定為標準輸入文件,從鍵盤上輸入就意味著從標準輸入文件上輸入數(shù)據(jù)。如scanf、getchar函數(shù)就屬于這類輸入。8.4.1打開文件

打開文件的庫函數(shù)是fopen。

聲明形式:FILEfopen(char*filename,char*mode)

函數(shù)功能:在內(nèi)存中為文件分配一個文件緩沖區(qū)。

參數(shù)說明:

Filename——字符串,包含欲打開的文件路徑及文件名;

Mode——字符串,說明打開文件的模式。

返回值:文件指針(NULL為異常,表示文件未打開)。

特別提示:文件打開后,應檢查此操作是否成功,即判斷文件指針是否為空(NULL),然后才能決定能否對文件繼續(xù)訪問。

表8.2文件打開模式說明:

(1)打開的文件分文本文件與二進制文件。

(2)文本文件用“t”表示(可省略);二進制文件用“b”表示。

在用戶希望保存原有文件內(nèi)容時,使用模式“w”來打開文件,使得文件的內(nèi)容丟失而沒有任何警告。

用不正確的文件模式來打開文件將導致破壞性的錯誤。例如,當應該用更新模式“r+”的時候用寫入模式“w”打開文件將刪除文件內(nèi)容。

文件的路徑

用戶在磁盤上尋找文件時,所歷經(jīng)的文件夾線路叫路徑。路徑分為絕對路徑和相對路徑。絕對路徑是完整的描述文件位置的路徑,它是從盤符開始的路徑。相對路徑是相對于目標位置的路徑,是指在當前的目錄下開始的路徑。

能唯一標識某個磁盤文件的字符串形式為:

盤符:\路徑\文件名.擴展名例1:我們要找c:\windows\system\config文件,如果當前在c:\winodws\,則相對路徑表示為system\config,絕對路徑表示為c:\windows\system\config。

例2:

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

表示相對路徑,無路徑信息,則a1.txt文件在當前目錄下(注:此時當前目錄為程序所在工程的目錄)。

fp=fopen("d:\\qyc\\a1.txt","r")

表示絕對路徑,a1.txt在d盤qyc目錄下。

注:此處用“\\”是因為在字符串中“\”是要用轉義字符表示的。8.4.2關閉文件

關閉文件的庫函數(shù)是fclose。

聲明形式:intfclose(FILE*fp);

函數(shù)功能:關閉文件指針指向的文件,將緩沖區(qū)數(shù)據(jù)做相應處理后釋放緩沖區(qū)。

輸出:如果關閉文件出錯,函數(shù)返回非零值;否則返回0。

特別提示:使用完文件后應及時關閉,否則可能會丟失數(shù)據(jù),因為寫文件時,只有當緩沖區(qū)滿時才將數(shù)據(jù)真正寫入文件,若當緩沖區(qū)未滿時結束程序運行,緩沖區(qū)中的數(shù)據(jù)將會丟失。

【例8-1】文件的例子1。

1 /*對data.txt文件寫入10條記錄*/

2 #include<stdio.h>

3 intmain()

4 {

5 FILE*fp;/*FILE為文件類型*/

6 inti;

7 intx;

8

9 fp=fopen("data.txt","w"); /*以文本寫方式"w"打開data.txt*/

10

11 for(i=1;i<=10;i++)

12 {

13 scanf("%d",&x);

14 fprintf(fp,"%d",x); /*將x輸出到fp指向的文件中*/

15 }

16 fclose(fp); /*關閉文件*/

17 return0;

18 }程序結果:程序運行結束,在程序文件所在工程的目錄下,可以找到新建的文件data.txt,打開后即可看到程序運行時從鍵盤輸入的10個數(shù)據(jù)。

文件存儲成為二進制還是文本文件取決于fopen的方式。如果用wt,則存儲為文本文件,這樣用記事本打開就可以正常顯示了;如果用wb,則存儲為二進制文件,這樣用記事本打開有可能會出現(xiàn)小方框,若要正常顯示,可以用寫字板或UltraEdit等工具打開。8.4.3文件的讀寫

對文件的讀寫有系列函數(shù),參見表8.3和表8.4。

表8.3文件讀寫函數(shù)(1)

表8.4文件讀寫函數(shù)(2)特別提示:文件的讀寫都是在文件的當前位置進行的。所謂當前位置,是指文件的數(shù)據(jù)讀寫指針在當前時刻指示的位置。文件打開時,該指針指向文件的開頭;一次讀寫完成后,該指針自動后移(移至本次讀寫數(shù)據(jù)的下一個字節(jié))。

【例8-2】文件的例子2。逐個按序讀出并顯示已有文件file.txt中的字符。

1 /*按序逐個讀出文件中的字符*/

2 #include<stdio.h>

3 #include<stdlib.h>

4

5 voidmain()

6 {

7 charch;

8 FILE*fp; /*定義一個文件類型的指針變量fp*/

9 fp=fopen("file.txt","r"); /*以只讀方式打開文本文件file.Txt*/

10 if(fp==NULL) /*打開文件失敗*/

11 {

12 printf("cannotopenthisfile\n");

13 exit(0); /*庫函數(shù)exit,終止程序*/

14 }

15 ch=fgetc(fp); /*讀出文件中的一個字符,賦給變量ch*/

16 while(ch!=EOF) /*判斷文件是否結束,此判斷條件等價于(!feof(fp))*/

17 {

18 putchar(ch); /*輸出從文件中讀出的字符*/

19 ch=fgetc(fp); /*讀出文件中的一個字符,賦給變量ch*/

20 }

21 fclose(fp); /*關閉文件*/

22 return0;

23 }

exit函數(shù):在<stdlib.h>中聲明,將強制程序結束。在檢測到輸入錯誤或者程序無法打開要處理的文件時使用。

exit(0)為正常退出,exit(1),為非正常退出(只要其中的參數(shù)不為零)。

C語言中的exit()和return有什么不同?

在主程序main中,語句return(表達式)等價于函數(shù)exit(表達式)。但是,函數(shù)exit有一個優(yōu)點,它可以從其他函數(shù)中調用,并且可以用查找程序查找這些調用。用exit()函數(shù)可以退出程序并將控制權返回給操作系統(tǒng),而用return語句可以從一個函數(shù)中返回并將控制權返回給調用該函數(shù)的函數(shù)。如果在main()函數(shù)中加入return語句,那么在執(zhí)行這條語句后將退出main()函數(shù)并將控制權返回給操作系統(tǒng),這樣的一條return語句和exit()函數(shù)的作用是相同的。

【例8-3】文件的例子3。將指定字符串寫到文件中;將文件中的字符串讀到數(shù)

組里。

1 /*將指定字符串寫到文件中*/

2 #include<stdio.h>

3 chars="Iamastudent"; /*設定字符串s*/

4 intmain()

5 {

6 chara[100];

7 FILE*fp; /*定義文件指針為fp*/

8 intn=strlen(s); /*計算字符串s的長度*/

9

10 /*以寫方式打開文本文件f1.txt*/

11 if((fp=fopen("f1.txt","w"))!=NULL)

12 {

13 fputs(s,fp); /*將s所指的字符串寫到fp所指的文件中*/

14 }

15 fclose(fp); /*關閉fp所指向的文件*/

16

17 /*以只讀方式打開文本文件f1.txt*/

18 fp=fopen("f1.txt","r");

19 fgets(a,n+1,fp); /*將fp所指的文件中的內(nèi)容讀到a中*/

20 printf("%s\n",a); /*輸出a中的內(nèi)容*/

21 fclose(fp); /*關閉fp所指向的文件*/

22 return0;

23 }說明:第19行語句fgets(a,n+1,fp)是將讀出的字符串放入a串中,其中a是已經(jīng)定義好的字符串,n+1是讓fp所指的文件內(nèi)容依次取n個字符給a,這n個字符恰為s串的內(nèi)容,之后還要在該串后自動加入一個'\0'字符,因此要寫n+1。

【例8-4】文件的例子4。向磁盤寫入格式化數(shù)據(jù),再從該文件讀出顯示到屏幕。

1 /*數(shù)據(jù)成塊寫入文件*/

2 #include"stdio.h"

3 #include"stdlib.h"

4

5 intmain()

6 {

7 FILE*fp1;

8 inti;

9 structstudent/*定義結構體*/

10 {

11 charname[15];

12 charnum[6];

13 floatscore[2];

14 }stu;

15

16 fp1=fopen("test.txt","wb");

17 if(fp1==NULL) /*以二進制只寫方式打開文件*/

18 {

19 printf("cannotopenfile");

20 exit(0);

21 }

22 printf("inputdata:\n");

23 for(i=0;i<2;i++)

24 {

25 /*輸入一行記錄*/

26 scanf("%s%s%f%f",

27 ,stu.num,&stu.score[0],&stu.score[1]);

28 /*成塊寫入文件,一次寫結構的一行*/

29 fwrite(&stu,sizeof(stu),1,fp1);

30 }

31 fclose(fp1);

32

33 /*重新以二進制只寫方式打開文件*/

34 if((fp1=fopen("test.txt","rb"))==NULL)

35 {

36 printf("cannotopenfile");

37 exit(0);

38 }

39 printf("outputfromfile:\n");

40 for(i=0;i<2;i++)

41 {

42 fread(&stu,sizeof(stu),1,fp1); /*從文件成塊讀*/

43 printf("%s%s%7.2f%7.2f\n", /*顯示到屏幕*/

44 ,stu.num,stu.score[0],stu.score[1]);

45 }

46 fclose(fp1);

47 return0;

48 }

程序結果:

inputdata:

xiaowangj00187.598.4

xiaolij00299.589.6

outputfromfile:

xiaowangj00187.5098.40

xiaolij00299.5089.60

把希望的內(nèi)容寫入文件后,查看文件時出現(xiàn)亂碼,這往往是文件操作函數(shù)要求的文件制式與你寫入時打開文件的制式不一致造成的。8.4.4文件位置的確定

確定文件位置的庫函數(shù)是fseek。

聲明形式:fseek(文件類型指針,位移量,起始點位置)

函數(shù)功能:重定位文件內(nèi)部指針的位置。以“起始點位置”為基準,按“位移量”指定字節(jié)數(shù)做偏移(起始位置值:文件頭0,當前位置1,文件尾2)。

返回值:成功返回0;失敗返回-1。

【例8-5】文件的例子5。已知stu_list.txt中存放了多個學生的信息,在此文件中讀出第二個學生的數(shù)據(jù)。

程序實現(xiàn):

1 /*在文件指定位置讀取數(shù)據(jù)——對文件進行隨機讀寫*/

2 #include"stdio.h"

3 #include"stdlib.h"

4

5 structstu/*學生信息結構*/

6 {

7 charname[10];

8 intnum;

9 intage;

10 charaddr[15];

11 }boy,*qPtr;/*定義結構變量boy,結構指針qPtr*/

12

13 intmain()

14 {

15 FILE*fp;

16 charch;

17 inti=1;/*跳過結構的前i行*/

18 qPtr=&boy;/*qPtr指向boy結構體的起始位置*/

19

20 if((fp=fopen("stu_list.txt","rb"))==NULL)

21 {

22 printf("Cannotopenfile!");

23 exit(0);

24 }

25 /*使文件的位置指針重新定位于文件開頭*/

26 rewind(fp);

27 /*從文件頭開始,向后移動i個結構大小的字節(jié)數(shù)*/

28 fseek(fp,i*sizeof(structstu),0);

29 /*從fp文件中讀出結構的當前行,放到qPtr指向的地址中*/

30 fread(qPtr,sizeof(structstu),1,fp);

31 printf("%st%5d%7d%sn",qPtr->name,

32 qPtr->num,qPtr->age,qPtr->addr);

33 return0;

34 }

(1)有的教材中提到:按文本方式或二進制方式中的某一種方式存儲的文件,使用時必須以原來的方式從外存中讀出,才能保證數(shù)據(jù)的正確性。

(2)程序設計錯誤:把希望的內(nèi)容寫入文件后,查看文件時出現(xiàn)亂碼,這往往是文件操作函數(shù)要求的文件制式與寫入文件時打開文件的制式不一致造成的。8.5關于文件讀寫的討論

這究竟是怎么回事呢?

以下按不同的情形來討論,要點:

(1)在不同文件打開模式(文本、二進制)狀態(tài)下,文件緩沖區(qū)中的數(shù)據(jù)是否正確。

(2)在不同文件打開模式(文本、二進制)狀態(tài)下,寫入文件中的數(shù)據(jù)是否顯示正常。

【情形一】以fprintf方式向文件data.txt寫入數(shù)據(jù),以fscanf方式讀出data.txt中的數(shù)據(jù)。

1 /*文件的讀寫方式*/

2 #include<stdio.h>

3 #include<stdlib.h>

4

5 intmain()

6 {

7 FILE*fp;/*FILE為文件類型*/

8 inti;

9 intx;

10 intb=0;

11

12 fp=fopen("data.txt","wb");/*以"wb"方式打開data.txt文件*/

13

14 if(fp==NULL) /*打開文件失敗*/

15 {

16 printf("1:cannotopenthisfile\n");

17 exit(0); /*庫函數(shù)exit終止程序*/

18 }

19 /****以fprintf格式寫入數(shù)據(jù)*****/

20 for(i=1;i<7;i++)

21 {

22 scanf("%d",&x);

23 fprintf(fp,"%d\n",x);/*將x輸出到fp指向的文件中*/

24 }

25 fclose(fp);/*關閉文件*/

26

27 fp=fopen("data.txt","r"); /*以只讀方式打開文本文件data.Txt*/

28 if(fp==NULL) /*打開文件失敗*/

29 {

30 printf("2:cannotopenthisfile\n");

31 exit(0); /*庫函數(shù)exit終止程序*/

32 }

33

34 /*********以fscanf方式從文件中讀出數(shù)據(jù)*********/

35 fscanf(fp,"%d",&x); /*讀出文件中的一個int型數(shù)值給x*/

36 while(!feof(fp)) /*判斷文件是否結束*/

37 {

38 printf("%d",x);

39 fscanf(fp,"%d",&x);

40 }

41 fclose(fp);/*關閉文件*/

42 return0;

43 }

程序結果:

輸入:234567

輸出:234567

【情形二】以fprintf方式向data.txt文件寫入數(shù)據(jù),以fgetc方式讀出data.txt中的數(shù)據(jù)。

分別用以下灰色框中的語句替代情形一中兩個灰色框的語句。

/****以fprintf格式寫入數(shù)據(jù)*****/

for(i=1;i<7;i++)

{

scanf("%d",&x);

fprintf(fp,"%d\n",x); /*將x輸出到fp指向的文件中*/

}

/*********以fgetc方式從文件中讀出的字符*********/

ch=fgetc(fp); /*讀出文件中的一個字符,賦給變量ch*/

while(ch!=EOF) /*判斷文件是否結束,此判斷條件等價于(!feof(fp))*/

{

putchar(ch); /*輸出從文件中讀出的字符*/

ch=fgetc(fp); /*讀出文件中的一個字符,賦給變量ch*/

}

程序結果:

輸入:

234567

輸出:

2

3

4

5

6

7

【情形三】以fwrite方式向文件data.txt寫入數(shù)據(jù),以fread方式讀出data.txt中的數(shù)據(jù)。

分別用以下灰色框中的語句替代情形一中兩個灰色框的語句。

/****以fwrite格式寫入數(shù)據(jù)*****/

for(i=1;i<7;i++) /*循環(huán)6次,把6個int型數(shù)據(jù)寫入文件*/

{

scanf("%d",&x);

fwrite(&x,sizeof(int),1,fp);/*將x輸出到fp指向的文件中*/

}

/****以fread格式讀出數(shù)據(jù)*****/

for(i=1;i<7;i++)

{

fread(&b,sizeof(int),1,fp);

printf("b=%x\n",b);

}

程序結果:

輸入:

234567

輸出:

b=2

b=3

b=4

b=5

b=6

b=7

查看文件緩沖區(qū)。圖8.3~圖8.8是分別為情形三的調試步驟1~調試步驟6。

圖8.3中,創(chuàng)建文件,文件指針fp為0x426af8。

圖8.4中,緩沖區(qū)_base地址是0x3851f0。

圖8.3情形三調試步驟1

圖8.4情形三調試步驟2圖8.5中,緩沖區(qū)_bass中的內(nèi)容為6個輸入的int數(shù)據(jù),一個int占4

byte。

圖8.6中,以讀方式打開文件,fp指針為0x426af8,同前面建立文件時是一樣的。注意緩沖區(qū)_base地址是0x3851f0,即同前面寫文件時也是一樣的。

_ptr(指向buffer中第一個未讀的字節(jié))指向的是0x3851f4,將要讀出的字節(jié)值為3。

圖8.5情形三調試步驟3圖8.6情形三調試步驟4

讀與寫用的是同一緩沖區(qū)。

圖8.7中,_ptr指向的是0x3851f8,將要讀出的字節(jié)值為4。

圖8.8中,緩沖區(qū)_base地址是0x3851f0,其中的內(nèi)容也依然未變。

圖8.7情形三調試步驟5

圖8.8調試步驟6

表8.5for循環(huán)相關量的變化表8.5中:

char*_ptr; /*指向buffer中第一個未讀的字節(jié)*/

int_cnt; /*記錄剩余未讀字節(jié)的個數(shù)*/

char*_base; /*指向一個字符數(shù)組,即這個文件的緩沖區(qū)*/

【情形四】以fprintf方式向文件data.txt寫入數(shù)據(jù),以fread方式讀出data.txt中的數(shù)據(jù)。省略的程序語句同情形一。

/****以fprintf格式寫入數(shù)據(jù)*****/

for(i=1;i<7;i++)

{

scanf("%d",&x);

fprintf(fp,"%d\n",x);/*將x輸出到fp指向的文件中*/

}

/**************以fread方式讀出數(shù)據(jù)***************/

for(i=1;i<4;i++)

{

fread(&b,sizeof(int),1,fp);

printf("b=%x\n",b);

}

程序結果:

輸入:

234567

輸出:

b=a330a32

b=a350a34

b=a370a36

情形一中,以fprintf方式寫入數(shù)據(jù),以fscanf方式讀出數(shù)據(jù);情形四中,以fprintf方式寫入數(shù)據(jù),以fread方式讀出數(shù)據(jù)。情形一的結果是正常的,為什么情形四的結果看起來就不對了呢?

答:跟蹤查看一下便知。

圖8.9、圖8.10所示分別為情形四的調試步驟1和調試步驟2。

圖8.9緩沖區(qū)的數(shù)據(jù)中,

0x0A是'\n'的ASCII碼,是語句fprintf(fp,"%d\n",x)中的'\n'產(chǎn)生的,同輸入的數(shù)字一起寫入到文件中。

圖8.9情形四調試步驟1圖8.10中,用fread(&b,sizeof(int),1,fp)語句讀緩沖區(qū)中的內(nèi)容時,是按照sizeof(int)等于4

byte的長度讀出并賦給變量b的。所以i=1時,b的值為從0x3851f0開始的4

byte的數(shù)值,即為0x0a330a32,對應十進制數(shù)為171117106。圖8.10情形四調試步驟2總之,無論文件的寫入方式、讀出方式是文本模式還是二進制模式,程序結果都如表8.6所示,即讀寫的文件模式不影響程序的結果。

表8.6讀寫方式與程序結果至于寫入data.txt文件的數(shù)據(jù)是否能正常查看,則與讀寫的文件模式有關,具體見表8.7。

表8.7data文件的顯示結果

(1)在文件緩沖區(qū)中的數(shù)據(jù)形式,與文件讀寫模式無關;

(2)程序生成的文件是否能正常顯示,與文件讀寫模式有關;

(3)若程序讀文件出現(xiàn)數(shù)據(jù)顯示不對,可以通過查看緩沖區(qū)數(shù)據(jù)的格式,選擇合適的操作函數(shù)。

當我們在設計好算法和程序后,要在調試環(huán)境中輸入測試數(shù)據(jù),查看程序運行的結果。由于調試往往不能一次成功,每次運行時,都要重新輸入一遍測試數(shù)據(jù),對于有大量輸入數(shù)據(jù)的題目,直接從鍵盤輸入數(shù)據(jù)需要花費大量時間。

8.6程序調試與數(shù)據(jù)測試文件我們可以把要輸入的數(shù)據(jù)事先放在文件中,用文件的讀函數(shù)讀入;將程序運行的結果用文件寫函數(shù)寫入指定的文件??梢愿鶕?jù)測試數(shù)據(jù)的特點選用文件讀寫函數(shù)。下面給出兩個代碼模板。

1.使用fscanf和fprintf函數(shù)

【代碼模板一】

#include<stdio.h>

intmain()

{

FILE*fp1,*fp2;

fp1=fopen("data.in","r"); /*以只讀方式打開輸入文件data.in*/

fp2=fopen("data.out","w"); /*以寫方式打開輸出文件data.out*/

/*中間按原樣寫代碼,把scanf改為fscanf,printf改為fprintf即可*/

fclose(fp1);

fclose(fp2);

return0;

}

2.使用freopen函數(shù)

聲明形式:FILE*freopen(constchar*path,constchar*mode,FILE*stream);

參數(shù)說明:

path——文件名,用于存儲輸入/輸出的自定義文件名;

mode——文件打開的模式,和fopen中的模式(如r為只讀,w為寫)相同;

stream——一個文件,通常使用標準流文件。

功能:實現(xiàn)重定向,把預定義的標準流文件定向到由path指定的文件中。返回值:成功,返回一個path所指定文件的指針;失敗,返回NULL。(一般不使用它的返回值。)

標準流文件

啟動一個C語言程序時,操作系統(tǒng)環(huán)境負責打開3個文件,并將這3個文件的指針提供給該程序。這3個文件指針分別為標準輸入stdin、標準輸出stdout和標準錯誤stderr。它們在<stdio.h>中聲明,其中:

stdin:標準輸入流,默認為鍵盤輸入;

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經(jīng)權益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
  • 6. 下載文件中如有侵權或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

最新文檔

評論

0/150

提交評論