? 鍵盤、顯示器、打印機(jī)、磁盤驅(qū)動器等邏輯設(shè)備, 其輸入輸出都可以通過文
件管理的方法來完成。而在編程時使用最多的要算是磁盤文件, 因此本節(jié)主要以
磁盤文件為主, 詳細(xì)介紹Turbo C2.0提供的文件操作函數(shù), 當(dāng)然這┒暈?zāi)件的?
作函數(shù)也適合于非磁盤文件的情況。
??? 另外, Turbo C2.0提供了兩類關(guān)于文件的函數(shù)。一類稱做標(biāo)準(zhǔn)文件函數(shù)也稱
緩沖型文件函數(shù), 這是ANSI標(biāo)準(zhǔn)定義的函數(shù); 另一類叫非標(biāo)準(zhǔn)文件函數(shù), 也稱非
緩沖型文件函數(shù)。這類函數(shù)最早公用于UNIX操作系統(tǒng), 但現(xiàn)在MS-DOS3.0 以上版
本的操作系統(tǒng)也可以使用。下面分別進(jìn)行介紹。
?
??? 1.2.1? 標(biāo)準(zhǔn)文件函數(shù)
??? 標(biāo)準(zhǔn)文件函數(shù)主要包括文件的打開、關(guān)閉、讀和寫等函數(shù)。不象BASIC 、
FORTRAN語方有順序文件和隨機(jī)文件之分,?? 在打開時就應(yīng)按不同的方式確定。
Turbo C2.0并不區(qū)分這兩種文件, 但提供了兩組函數(shù), 即順序讀寫函數(shù)和隨機(jī)讀
寫函數(shù)。
??? 一、文件的打開和關(guān)閉
??? 任何一個文件在使用之前和使用之后, 必須要進(jìn)行打開和關(guān)閉, 這是因為操
作系統(tǒng)對于同時打開的文件數(shù)目是有限制的, DOS操作系統(tǒng)中,??? 可以在DEVICE
.SYS中定義允許同時打開的文件數(shù)n(用files=n定義)。其中n 為可同時打開的文
件數(shù), 一般n<=20。因此在使用文件前應(yīng)打開文件, 才可對其中的信息進(jìn)行存取。
用完之后需要關(guān)閉, 否則將會出現(xiàn)一些意想不到的錯誤。Turbo C2.0提供了打開
和關(guān)閉文件的函數(shù)。

??? 1. fopen()函數(shù)
??? fopen函數(shù)用于打開文件, 其調(diào)用格式為:
???? FILE *fopen(char *filename, *type);
??? 在介紹這個函數(shù)之;前, 先了解一下下面的知識。
??? (1) 流(stream)和文件(file)
??? 流和文件 在Turbo C2.0中是有區(qū)別的, Turbo C2.0 為編程者和被訪問的設(shè)
備之間提供了一層抽象的東西, 稱之為"流", 而將具體的實際設(shè)備叫做文件。
流是一個邏輯設(shè)備, 具有相同的行為。因此, 用來進(jìn)行磁盤文件寫的函數(shù)也同樣
可以用來進(jìn)行打印機(jī)的寫入。在Turbo C2.0中有兩種性質(zhì)的流:?? 文字流( text
stream)和二進(jìn)制(binary stream)。對磁盤來說就是文本文件和二進(jìn)制文件。本
軟件為了便于讓讀者易理解Turbo C2.0語言而沒有對流和文件作特別區(qū)分。
??? (2) 文件指針FILE
??? 實際上FILE是一個新的數(shù)據(jù)類型。它是Turbo C2.0的基本數(shù)據(jù)類型的集合,
稱之為結(jié)構(gòu)指針。有關(guān)結(jié)構(gòu)的概念將在第四節(jié)中詳細(xì)介紹, 這里只要將FILE理解
為一個包括了文件管理有關(guān)信息的數(shù)據(jù)結(jié)構(gòu), 即在打開文件時必須先定義一個文
件指針。
??? (3) 以后介紹的函數(shù)調(diào)用格式將直接寫出形式參數(shù)的數(shù)據(jù)類型和函數(shù)返回值
的數(shù)據(jù)類型。例如: 上面打開文件的函數(shù), 返回一個文件指針, 其中形式參數(shù)有
兩個, 均為字符型變量(字符串?dāng)?shù)組或字符串指針)。本軟件不再對函數(shù)的調(diào)用格
式作詳細(xì)說明。
??? 現(xiàn)在再來看打開文件函數(shù)的用法。
??? fopen()函數(shù)中第一個形式參數(shù)表示文件名, 可以包含路徑和文件名兩部分。
如:
???? "B:TEST.DAT"
???? "C:\\TC\\TEST.DAT"
??? 如果將路徑寫成"C:\TC\TEST.DAT"是不正確的, 這一點要特別注意。
??? 第二個形式參數(shù)表示打開文件的類型。關(guān)于文件類型的規(guī)定參見下表。
?????????????????????? 表? 文件操作類型
??? ━━━━━━━━━━━━━━━━━━━━━━━━━━━━
????????? 字符??????????????? 含義
??? ────────────────────────────
?????????? "r"?????????? 打開文字文件只讀
?????????? "w"?????????? 創(chuàng)建文字文件只寫
?????????? "a"?????????? 增補(bǔ), 如果文件不存在則創(chuàng)建一個
?????????? "r+"????????? 打開一個文字文件讀/寫
?????????? "w+"????????? 創(chuàng)建一個文字文件讀/寫
?????????? "a+"????????? 打開或創(chuàng)建一個文件增補(bǔ)
?????????? "b"?????????? 二進(jìn)制文件(可以和上面每一項合用)
?????????? "t"?????????? 文這文件(默認(rèn)項)
??? ━━━━━━━━━━━━━━━━━━━━━━━━━━━━
??? 如果要打開一個CCDOS子目錄中, 文件名為CLIB的二進(jìn)制文件, 可寫成:
???? fopen("c:\\ccdos\\clib", "rb");
??? 如果成功的打開一個文件, fopen()函數(shù)返回文件指針,?? 否則返回空指針
(NULL)。由此可判斷文件打開是否成功。
??? 2. fclose()函數(shù)
??? fclose()函數(shù)用來關(guān)閉一個由fopen()函數(shù)打開的文件 , 其調(diào)用格式為:
????? int fclose(FILE *stream);
??? 該函數(shù)返回一個整型數(shù)。當(dāng)文件關(guān)閉成功時, 返回0, 否則返回一個非零值。
可以根據(jù)函數(shù)的返回值判斷文件是否關(guān)閉成功。
??? 例10:
???? #iclude<stdio.h>
???? main()
???? {
????????? FILE *fp;??????????????? /*定義一個文件指針*/
????????? int i;
????????? fp=fopen("CLIB", "rb");? /*打開當(dāng)前目錄名為CLIB的文件只讀*/
????????? if(fp==NULL)???????????? /*判斷文件是否打開成功*/
???????????? puts("File open error");/*提示打開不成功*/
????????? i=fclose(fp);??????????? /*關(guān)閉打開的文件*/
????????? if(i==0)???????????????? /*判斷文件是否關(guān)閉成功*/
??????????? printf("O,K");???????? /*提示關(guān)閉成功*/
????????? else
??????????? puts("File close error");/*提示關(guān)閉不成功*/
???? }

??? 二、有關(guān)文件操作的函數(shù)
??? 本節(jié)所講的文件讀寫函數(shù)均是指順序讀寫, 即讀寫了一條信息后, 指針自動
加1。下面分別介紹寫操作函數(shù)和讀操作函數(shù)。

??? 1. 文件的順序?qū)懞瘮?shù)
??? fprintf()、fputs()和fputc()函數(shù)
??? 函數(shù)fprintf()、fputs()和fputc()均為文件的順序?qū)懖僮骱瘮?shù),? 其調(diào)用格
式如下:
??? int fprintf(FILE *stream, char *format, <variable-list>);
??? int fputs(char *string, FILE *steam);
??? int fputc(int ch, FILE *steam);
??? 上述三個函數(shù)的返回值均為整型量。fprintf() 函數(shù)的返回值為實際寫入文
件中的字罕個數(shù)(字節(jié)數(shù))。如果寫錯誤, 則返回一個負(fù)數(shù), fputs()函數(shù)返回0時
表明將string指針?biāo)傅淖址畬懭胛募械牟僮鞒晒? 返回非0時,? 表明寫操
作失敗。fputc()函數(shù)返回一個向文件所寫字符的值, 此時寫操作成功,? 否則返
回EOF(文件結(jié)束結(jié)束其值為-1, 在stdio.h中定義)表示寫操作錯誤。
???? fprintf( ) 函數(shù)中格式化的規(guī)定與printf( ) 函數(shù)相同,?? 所不同的只是
fprintf()函數(shù)是向文件中寫入。而printf()是向屏幕輸出。
??? 下面介紹一個例子, 運(yùn)行后產(chǎn)后一個test.dat的文件。
??? 例11:
???? #include<stdio.h>
???? main()
???? {
????????? char *s="That's good news");? /*定義字符串指針并初始化*/
????????? int i=617;??????????????????? /*定義整型變量并初始化*/
????????? FILE *fp;???????????????????? /*定義文件指針*/
????????? fp=fopne("test.dat", "w");??? /*建立一個文字文件只寫*/
????????? fputs("Your score of TOEFLis", fp);/*向所建文件寫入一串字符*/
????????? fputc(':', fp);?????????????? /*向所建文件寫冒號:*/
????????? fprintf(fp, "%d\n", i);?????? /*向所建文件寫一整型數(shù)*/
????????? fprintf(fp, "%s", s);???????? /*向所建文件寫一字符串*/
????????? fclose(fp);?????????????????? /*關(guān)閉文件*/
???? }
??? 用DOS的TYPE命令顯示TEST.DAT的內(nèi)容如下所示:
??? 屏幕顯示
????? Your score of TOEFL is: 617
????? That's good news

??? 2. 文件的順序讀操作函數(shù)
??? fscanf()、fgets()和fgetc()函數(shù)
??? 函數(shù)fscanf()、fgets()和fgetc()均為文件的順序讀操作函數(shù), 其調(diào)用格式
如下:
???? int fscanf(FILE *stream, char *format, <address-list>);
???? char fgets(char *string, int n, FILE *steam);
???? int fgetc(FILE *steam);
??? fscanf()函數(shù)的用法與scanf()函數(shù)相似,?? 只是它是從文件中讀到信息。
fscanf()函數(shù)的返回值為EOF(即-1), 表明讀錯誤, 否則讀數(shù)據(jù)成功。fgets()函
數(shù)從文件中讀取至多n-1個字符(n用來指定字符數(shù)), 并把它們放入string指向的
字符串中, 在讀入之后自動向字符串未尾加一個空字符, 讀成功返回string指針,
失敗返回一個空指針。fgetc()函數(shù)返回文件當(dāng)前位置的一個字符,? 讀錯誤時返
回EOF。
??? 下面程序讀取例11產(chǎn)生的test.dat文件, 并將讀出的結(jié)果顯示在屏幕上。
??? 例12
???? #include<stdio.h>
???? main()
???? {
????????? char *s, m[20];
????????? int i;
????????? FILE? *fp;
????????? fp=fopen("test.dat", "r");??? /*打開文字文件只讀*/
????????? fgets(s, 24, fp);???????????? /*從文件中讀取23個字符*/
????????? printf("%s", s);????????????? /*輸出所讀的字符串*/
????????? fscanf(fp, "%d", &i);???????? /*讀取整型數(shù)*/
????????? printf("%d", i);????????????? /*輸出所讀整型數(shù)*/
????????? putchar(fgetc(fp));?????????? /*讀取一個字符同時輸出*/
????????? fgets(m, 17, fp);???????????? /*讀取16個字符*/
????????? puts(m);????????????????????? /*輸出所讀字符串*/
????????? fclose(fp);?????????????????? /*關(guān)閉文件*/
????????? getch();????????????????????? /*等待任一鍵*/
???? }
??? 運(yùn)行后屏幕顯示:
??? Your score of TOEFL is: 617
??? That's good news
??? 如果將上例中fscanf(fp, "%d", &i)改為fscanf(fp, "%s", m),? 再將其后
的輸出語句改為printf("%s", m), 則可得出同樣的結(jié)果。由此可見Turbo C2. 0
中只要是讀文字文件, 則不論是字符還是數(shù)字都將按其ASCII值處理。 另外還要
說明的一點就是fscanf()函數(shù)讀到空白符時, 便自動結(jié)束, 在使用時要特別注意。

??? 3. 文件的隨機(jī)讀寫
??? 有時用戶想直接讀取文件中間某處的信息, 若用文件的順序讀寫必須從文件
頭開始直到要求的文件位置再讀, 這顯然不方便。Turbo C2.0提供了一組文件的
隨機(jī)讀寫函數(shù), 即可以將文件位置指針定位在所要求讀寫的地方直接讀寫。
??? 文件的隨機(jī)讀寫函數(shù)如下:
??? int fseek (FILE *stream, long offset, int fromwhere);
??? int fread(void *buf, int size, int count, FILE *stream);
??? int fwrite(void *buf, int size, int count, FILE *stream);
??? long ftell(FILE *stream);
??? fseek()函數(shù)的作用是將文件的位置指針設(shè)置到從fromwhere開始的第offset
字節(jié)的位置上, 其中fromwhere是下列幾個宏定義之一:
??? 文件位置指針起始計算位置fromwhere
━━━━━━━━━━━━━━━━━━━━━━━━━━━
??? 符號常數(shù)??????? 數(shù)值?????????? 含義
───────────────────────────
??? SEEK_SET????????? 0??????? 從文件開頭
??? SEEK_CUR????????? 1??????? 從文件指針的現(xiàn)行位置
??? SEEK_END????????? 2??????? 從文件末尾
━━━━━━━━━━━━━━━━━━━━━━━━━━━
??? offset是指文件位置指針從指定開始位置(fromwhere指出的位置)跳過的字
節(jié)數(shù)。它是一個長整型量, 以支持大于64K字節(jié)的文件。fseek()函數(shù)一般用于對
二進(jìn)制文件進(jìn)行操作。
??? 當(dāng)fseek()函數(shù)返回0時表明操作成功, 返回非0表示失敗。
??? 下面程序從二進(jìn)制文件test_b.dat中讀取第8個字節(jié)。
??? 例13:
???? #include<stdio.h>
???? main()
???? {
????????? FILE *fp;
????????? if((fp=fopen("test_b.dat", "rb"))==NULL)
??????????? {
????????????? printf("Can't open file");
????????????? exit(1);
??????????? }
????????? fseek(fp, 8. 1, SEEK_SET);
????????? fgetc(fp);
????????? fclose(fp);
???? }
??? fread()函數(shù)是從文件中讀count個字段, 每個字段長度為size個字節(jié), 并把
它們存放到buf指針?biāo)傅木彌_器中。
??? fwrite()函數(shù)是把buf指針?biāo)傅木彌_器中, 長度為size個字節(jié)的count個字
段寫到stream指向的文件中去。
??? 隨著讀和寫字節(jié)數(shù)的增大, 文件位置指示器也增大, 讀多少個字節(jié), 文件位
置指示器相應(yīng)也跳過多少個字節(jié)。讀寫完畢函數(shù)返回所讀和所寫的字段個數(shù)。
??? ftell()函數(shù)返回文件位置指示器的當(dāng)前值,? 這個值是指示器從文件頭開始
算起的字節(jié)數(shù), 返回的數(shù)為長整型數(shù), 當(dāng)返回-1時, 表明出現(xiàn)錯誤。
??? 下面程序把一個浮點數(shù)組以二進(jìn)制方式寫入文件test_b.dat中。
??? 例14:
???? #include <stdio.h>
???? main()
???? {
????????? float f[6]={3.2, -4.34, 25.04, 0.1, 50.56, 80.5};
???????????????????????? /*定義浮點數(shù)組并初始化*/
????????? int i;
????????? FILE *fp;
????????? fp=fopen("test_b.dat", "wb"); /*創(chuàng)建一個二進(jìn)制文件只寫*/
????????? fwrite(f, sizeof(float), 6, fp);/*將6個浮點數(shù)寫入文件中*/
????????? fclose(fp);?????????????????? /*關(guān)閉文件*/
???? }
??? 下面例子從test_b.dat文件中讀100個整型數(shù), 并把它們放到dat數(shù)組中。
??? 例15:
???? #include <stdio.h>
???? main()
???? {
????????? FILE *fp;
????????? int dat[100];
????????? fp=fopen("test_b.dat", "rb");/*打開一個二進(jìn)制文件只讀*/
????????? if(fread(dat, sizeof(int), 100, fp)!=100)
??????????????????????????????????????? /*判斷是否讀了100個數(shù)*/
??????????? {
?????????????? if(feof(fp))
???????????????? printf("End of file"); /*不到100個數(shù)文件結(jié)束*/
?????????????? else
???????????????? printf("Read error");? /*讀數(shù)錯誤*/
????????? fclose(fp);?????????????????? /*關(guān)閉文件*/
???? }
??? 注意:
??? 當(dāng)用標(biāo)準(zhǔn)文件函數(shù)對文件進(jìn)行讀寫操作時, 首先將所讀寫的內(nèi)容放進(jìn)緩沖區(qū),
即寫函數(shù)只對輸出緩沖區(qū)進(jìn)行操作, 讀函數(shù)只對輸入緩沖區(qū)進(jìn)行操作。例如向一
個文件寫入內(nèi)容, 所寫的內(nèi)容將首先放在輸出緩沖區(qū)中, 直到輸出緩沖區(qū)存滿或
使用fclose()函數(shù)關(guān)閉文件時, 緩沖區(qū)的內(nèi)容才會寫入文件中。若無fclose()
函數(shù), 則不會向文件中存入所寫的內(nèi)容或?qū)懭氲奈募?nèi)容不全。有一個對緩沖區(qū)
進(jìn)行刷新的函數(shù), 即fflush(), 其調(diào)用格式為:
??? int fflush(FILE *stream);
??? 該函數(shù)將輸出緩沖區(qū)的內(nèi)容實際寫入文件中, 而將輸入緩沖區(qū)的內(nèi)容清除掉。

??? 4. feof()和rewind()函數(shù)
??? 這兩個函數(shù)的調(diào)用格式為:
???? int feof(FILE *stream);
???? int rewind(FILE *stream);
??? feof()函數(shù)檢測文件位置指示器是否到達(dá)了文件結(jié)尾,? 若是則返回一個非0
值, 否則返回0。這個函數(shù)對二進(jìn)制文件操作特別有用, 因為二進(jìn)制文件中,? 文
件結(jié)尾標(biāo)志EOF也是一個合法的二進(jìn)制數(shù),? 只簡單的檢查讀入字符的值來判斷文
件是否結(jié)束是不行的。如果那樣的話, 可能會造成文件未結(jié)尾而被認(rèn)為結(jié)尾, 所
以就必須有feof()函數(shù)。
??? 下面的這條語句是常用的判斷文件是否結(jié)束的方法。
???? while(!feof(fp))
??????? fgetc(fp);
??? while為循環(huán)語句, 將在下面介紹。
??? rewind()函數(shù)用于把文件位置指示器移到文件的起點處, 成功時返回0,? 否
則, 返回非0值。
?

??? 1.2.2? 非標(biāo)準(zhǔn)文件函數(shù)
??? 這類函數(shù)最早用于UNIX操作系統(tǒng), ANSI標(biāo)準(zhǔn)未定義,?? 但有時也經(jīng)常用到,
DOS 3.0以上版本支持這些函數(shù)。它們的頭文件為io.h。
??? 一、文件的打開和關(guān)閉
??? 1. open()函數(shù)
??? open()函數(shù)的作用是打開文件, 其調(diào)用格式為:
???? int open(char *filename, int access);
??? 該函數(shù)表示按access的要求打開名為filename的文件, 返回值為文件描述字,
其中access有兩部分內(nèi)容: 基本模式和修飾符, 兩者用" "("或")方式連接。修
飾符可以有多個, 但基本模式只能有一個。access的規(guī)定如表3-2。
?????????????? 表 access的規(guī)定
━━━━━━━━━━━━━━━━━━━━━━━━━━━━
基本模式??? 含義??? 修飾符???????? 含? 義
────────────────────────────
O_RDONLY??? 只讀?? O_APPEND?? 文件指針指向末尾
O_WRONLY??? 只寫?? O_CREAT??? 文件不存在時創(chuàng)建文件,
????????????????????????????? 屬性按基本模式屬性
O_RDWR????? 讀寫?? O_TRUNC??? 若文件存在, 將其長度
????????????????????????????? 縮為0, 屬性不變
?????????????????? O_BINARY?? 打開一個二進(jìn)制文件
?????????????????? O_TEXT???? 打開一個文字文件
━━━━━━━━━━━━━━━━━━━━━━━━━━━━
??? open()函數(shù)打開成功, 返回值就是文件描述字的值(非負(fù)值), 否則返回-1。

??? 2. close()函數(shù)
??? close()函數(shù)的作用是關(guān)閉由open()函數(shù)打開的文件, 其調(diào)用格式為:
???? int close(int handle);
??? 該函數(shù)關(guān)閉文件描述字handle相連的文件。

??? 二、讀寫函數(shù)
??? 1. read()函數(shù)
??? read()函數(shù)的調(diào)用格式為:
???? int read(int handle, void *buf, int count);
??? read()函數(shù)從handle(文件描述字)相連的文件中, 讀取count個字節(jié)放到buf
所指的緩沖區(qū)中, 返回值為實際所讀字節(jié)數(shù), 返回-1表示出錯。返回0 表示文件
結(jié)束。

??? 2. write()函數(shù)
??? write()函數(shù)的調(diào)用格式為:
???? int write(int handle, void *buf, int count);
??? write()函數(shù)把count個字節(jié)從buf指向的緩沖區(qū)寫入與handle相連的文件中,
返回值為實際寫入的字節(jié)數(shù)。
?
??? 三、隨機(jī)定位函數(shù)
??? 1. lseek()函數(shù)
??? lseek()函數(shù)的調(diào)用格式為:
???? int lseek(int handle, long offset, int fromwhere);
??? 該函數(shù)對與handle相連的文件位置指針進(jìn)行定位, 功能和用法與fseek() 函
數(shù)相同。

??? 2. tell()函數(shù)
??? tell()函數(shù)的調(diào)用格式為:
???? long tell(int handle);
??? 該函數(shù)返回與handle相連的文件現(xiàn)生位置指針, 功能和用法與ftell()相同。