C文件的有關基礎知識
文件(file)是程序設計中的一個重要概念。所謂“文件”一般指存儲在外部介質上數據的集合。一批數據是以文件的形式存放在外部介質(如磁盤)上的。操作系統是以文件爲單位對數據進行管理的,也就是說,如果想找存放在外部介質上的數據,必須按照文件名找到所指定的文件,然後再從該文件中讀取數據。要向外部介質上存儲數據也必須先建立一個文件(以文件名作標誌),才能向它輸出數據。
從C程序的觀點來看,無論程序一次讀寫一個字符,或一行文字,或一個指定的數據區,作爲輸入輸出的各種文件或設備都是統一以邏輯數據流的方式出現的。
C的數據文件由一連串的字符(或字節)組成,而不考慮行的界限,兩行數據間不會自動加分隔符,對文件的存取是以字符(字節)爲單位的。輸入輸出數據流的開始和結束僅受程序控制而不受物理符號(如回車換行符)控制,這就增加了處理的靈活性。這種文件稱爲流式文件。
C語言採用“緩衝文件系統”處理數據文件,所謂緩衝文件系統是指系統自動的在內存區爲程序中每一個正在使用的文件開闢一個文件緩衝區。從內存向磁盤輸出數據必須先送到內存的緩衝區,裝滿緩衝區後才一起送到磁盤去。如果從磁盤向計算機讀入數據,則一次從磁盤文件將一批數據輸入到內存緩衝區(充滿緩衝區),然後再從緩衝區逐個地將數據送到程序數據區(給程序變量)。
每個被使用的文件都在內存中開闢一個相應的文件信息區,用來存放文件的有關信息,這些信息是保存在一個結構體變量中的。該結構體類型是由系統聲明的,取名爲FILE。
不同的C編譯系統的FILE類型包含的內容不完全相同,但大同小異。對以上結構體中的成員及其含義可不深究,只須知道其中存放文件的有關信息即可。
下面定義一個指向文件型數據的指針變量
FILE *fp;
定義fp是一個指向FILE類型數據的指針變量。可以使fp指向某一個文件的文件信息區(是一個結構體變量),通過該文件信息區中的信息就能夠訪問該文件。也就是說,通過文件指針變量就能夠找到與它關聯的文件。
注意:指向文件的指針變量並不是指向外部介質上的數據文件的開頭,而是指向內存中的文件信息區的開頭。
打開與關閉文件
所謂“打開”,是指爲文件建立相應的信息區和文件緩衝區。在編寫程序時,在打開文件的同時,一般都指定一個指針變量指向該文件,也就是建立起指針變量與文件之間的聯繫,這樣就可以通過該指針變量對文件進行讀寫了。所謂“關閉”是指撤銷文件信息區和文件緩衝區,使文件指針變量不再指向該文件。
用fopen函數打開數據文件
fopen函數的調用方式爲:
fopen(文件名,使用文件方式);
fopen函數的返回值是指向文件的指針(即該文件信息區的起始地址)。通常將fopen函數的返回值賦給一個指向文件的指針變量。如
FILE *fp; //定義一個指向文件的指針變量fp fp=fopen("idooi.txt","r"); //將fopen函數的返回值賦給指針變量fp
表1.使用文件的方式
文件使用方式 | 含義 | 當指定文件不存在 |
r 只讀 | 爲了輸入數據,打開一個已經存在的文本文件 | 出錯 |
w 只寫 | 爲了輸出數據,打開一個文本文件 | 建立新文件 |
a 追加 | 向文本文件尾添加數據 | 出錯 |
rb 只讀 | 爲了輸入數據,打開一個二進制文件 | 出錯 |
wb 只寫 | 爲了輸出數據,打開一個二進制文件 | 建立新文件 |
ab 追加 | 向二進制文件尾添加數據 | 出錯 |
r+ 讀寫 | 爲了讀和寫,打開一個文本文件 | 出錯 |
w+ 讀寫 | 爲了讀和寫,建立一個新的文本文件 | 建立新文件 |
a+ 讀寫 | 爲了讀和寫,打開一個文本文件 | 出錯 |
用fclose函數關閉數據文件
fclose函數調用的一般形式爲
fclose(文件指針);
如果不關閉文件將會丟失數據。因爲,在向文件寫數據時,是先將數據輸出到緩衝區,待緩衝區充滿後才正式輸出給文件。如果當數據未充滿緩衝區而程序結束運行,就有可能使緩衝區中的數據丟失。要用fclose函數關閉文件,先把緩衝區中的數據輸出到磁盤文件,然後才撤銷文件信息區。
fclose函數也帶回一個返回值,當成功地執行了關閉操作,則返回值爲0;否則返回EOF(-1)。
順序讀寫數據文件
向一個文件讀寫字符
表2.讀寫一個字符的函數
函數名 | 調用形式 | 功能 | 返回值 |
fgetc | fgetc(fp) | 從fp指向的文件讀入一個字符 | 成功則帶回所讀字符,失敗則返回EOF |
fputc | fputc(ch,fp) | 將ch寫到fp指向的文件中 | 成功返回輸出的字符,失敗則返回EOF |
向一個文件讀寫字符串
C語言允許通過函數fgets和fputs一次讀寫一個字符串。
表3.讀寫一個字符串的函數
函數名 | 調用形式 | 功能 | 返回值 |
fgets | fgets(str,n,fp) | 從fp指向的一個文件讀入一個長度爲(n-1)的字符串,存放到字符數組str中。 | 成功返回地址str,失敗返回NULL |
fputs | fputs(str,fp) | 把str所指向的字符串寫到fp指向的文件中 | 成功返回0,失敗返回非0的值 |
1.fgets函數的函數原型爲:
char * fgets(char *str, int n, FILE *fp);
其作用是從一個文件中讀取一個字符串。其中n是要求得到的字符的個數,但實際上只從fp所指向的文件中讀取n-1個字符,然後在最後加上'\0'。如果在讀完n-1個字符之前遇到換行符'\n'或文件結束符EOF,讀入即結束,但將所遇到的換行符也作爲一個字符讀入。若執行fgets函數成功,則返回值爲str,如果以開始就遇到文件尾或讀數據出錯,則返回NULL。
2.fputs函數的函數原型爲:
int fputs(char *str, FILE *fp);
其作用是將str所指向的字符串輸出到fp所指向的文件中。
fputs函數的第一個參數可以是字符串常量、字符數組名或者字符型指針。字符串末位的'\0'不輸出。若輸出成功,則返回0;失敗時,返回EOF。
用格式化方式讀寫文件
在對文件進行格式化輸入輸出時,可以使用fprintf和fscanf函數。它們的作用與printf和scanf函數相仿,都是格式化讀寫函數。它們的一般調用方式爲:
fprintf(文件指針,格式字符串,輸出表列); fscanf(文件指針,格式字符串,輸入表列);
用函數fprintf和fscanf對磁盤文件讀寫,使用方便,容易理解,但由於在輸入時要將文件中的ASCII碼轉換爲二進制形式再保存到內存變量中,在輸出時又要將內存中的二進制形式轉換成字符,要花費較多的時間。因此,在內存與磁盤頻繁交換數據的情況下,最好不用fprintf函數和fscanf函數,而是用下面的fread函數和fwrite函數進行二進制的讀寫。
用二進制形式向文件讀寫一組數據
程序常常需要一次輸入輸出一組數據(如數組和結構體變量的值),C語言允許用fread函數從文件中讀取一個數據塊,用fwrite函數向文件寫一個數據塊。在讀寫時是以二進制形式進行的。
它們的一般調用形式爲:
fread(buffer, size, count, fp); fwrite(buffer, size, count, fp);
其中:
buffer:是一個地址。對fread來說,它是用來存放從文件讀入的數據的存儲區的地址。對fwrite來說,是要把此地址開始的存儲區中的數據向文件輸出(以上指起始地址)。
size:要讀寫的字節數。
count:要讀寫多少個數據項(每個數據項的長度爲size)。
fp:FILE類型指針。
隨機讀寫數據文件
爲了對讀寫進行控制,系統爲每個文件設置了一個文件讀寫位置標記(簡稱文件標記),用來指示“接下來要讀寫的下一個字符的位置”。
可以根據讀寫的需要,人爲地移動文件位置標記的位置,然後對該位置進行讀寫,即隨機讀寫。
對流式文件既可以進行順序讀寫,也可以進行隨機讀寫。
文件位置標記的定位
可以強制使文件位置標記指向人們指定的位置。可以用以下函數實現:
1.用rewind函數使文件標記指向文件開頭。
rewind函數的作用是使文件標記重新返回文件的開頭,沒有返回值。
2.用fseek函數改變文件標記
fseek函數的調用形式爲:
fseek(文件類型指針,位置量,起始點);
“起始點”用0、1或2代替,見下表。
表4.
起始點 | 名字 | 用數字代表 |
文件開始位置 | SEEK_SET | 0 |
文件當前位置 | SEEK_CUR | 1 |
文件末位位置 | SEEK_END | 2 |
“位移量”指以“起始點”爲基點,向前移動的字節數。位移量是long型數據。
fseek函數一般用於二進制文件。下面是fseek函數調用的例子:
fseek(fp, 100L, 0); //向前移到離文件開頭100個字節處 fseek(fp, 50L, 1); //向前移到離當前位置50個字節處 fseek(fp, -10L, 2); //從文件末尾處向後移動10個字節
3.用ftell函數測定文件位置標記的當前位置
ftell函數的作用是得到流式文件中文件位置標記的當前位置。
由於文件中的文件標記經常移動,人們往往不容易知道其當前的位置,所以常用ftell函數得到當前的位置,用相對於文件開頭的位移量來表示。如果調用函數時出錯,返回-1L。
文件讀寫的出錯檢測
1.ferror函數
在調用各種輸入輸出函數時,如果出現錯誤,除了函數值有所反應外,還可以用ferror函數來檢查。它的一般調用形式爲:
ferror(fp);
若果返回值爲0,表示未出錯;如果返回一個非零值,表示出錯。
應該注意,對同一個文件每一次調用輸入輸出函數,都會產生一個新的ferror函數值,因此,應當在調用一個輸入輸出函數後立即檢查ferror的值,否則信息會丟失。
2.clearerr函數
clearerr函數的作用是使文件錯誤標誌和文件結束標誌置爲0。
只要出現文件讀寫錯誤標誌,它就一直保留,直到對同一文件調用clearerr函數或rewind函數,或任何其他一個輸入輸出函數。