//本文章為C/C++程式設計研習班課後心得摘要
硬碟(或其他儲存裝置)都只單純是區塊儲存媒體(block storage)並沒有甚麼檔案或目錄的機構存在,而檔案系統(file system)是作業系統提供的功能,檔案系統紀錄了目錄結構、甚麼檔名對應到硬碟上哪些塊空間、硬碟上哪些空間已經被檔案佔用了不可以覆蓋掉。
檔案分為二進位檔案和文字檔案
二進位檔案 (Binary File)
檔案中的一切資料都被當作原始資料。
與文字檔案 (Text file)
檔案中的資料被解讀成可顯示的字元和一些換行或列印控制字元。
檔案的操作都必須透過作業系統,分成open、read/write、close。
開啟檔案 (open)
告訴作業系統檔案被使用了,請紀錄他的狀態,互斥性的檔案請阻止其他程式使用。
讀取, 寫入檔案 (read/write)
檔案內容變更了,作業系統請從磁碟中找額外的儲存區塊,寫入中的檔案請阻止其他程式讀取。
關閉檔案 (close)
告訴作業系統檔案使用結束。
C語言中,開啟、讀寫、關閉檔案函式,把檔案分為文字檔案、2進位檔開啟。
二進位檔開啟
標準函式庫的檔案處理函式庫,都在 stdio.h 當中,所以必須 #include <stdio.h>,在當中有一個 FILE 結構體,標準函式庫的函式用它來紀錄已開啟檔案的一切資訊,包括目前的讀取位置,所以要以二進位檔的方式開啟一個檔案以供讀取:
//標準函式庫寫在stdio.h中,有用到要宣告 #include <stdio.h>。另外,在stdio.h有個FILE結構體,函式用他來記錄開啟檔案。
FILE *stream =fopen("檔案名稱", "rb");
它傳回一個內部結構體 FILE 的指標,你必須保留這個指標,但是不要去操作它的內容。如果無法開啟檔案(例如檔案不存在)則傳回 NULL,其中的 "rb" 參數指定檔案要以二進位檔模式開啟,你也可以此方式把文字檔當作二進位檔案開啟,然後就可以 fread( ) 函式來讀取內容。
原型: size_t fread( void * buffer, size_t size, size_t count, FILE * stream );
參數
- buffer : 儲存讀取資料的記憶體空間。//有緩衝區的輸出入,輸出入>>緩衝區(buffer)>>磁碟
- size : 讀取的單位長度,例如下例的 sizeof(int)。
- count : 讀取的個數,下例只讀取1個整數。
- stream : 以 fopen( ) 獲得的 FILE * 內部結構體指標。
傳回值:
讀取到的 bytes,如果檔案斷掉可能會少於size*count bytes ( 跟除法原理一樣啦 ) ,可以用來判斷檔案是否不完整。
例如讀取一個整數:
原型:fread(&a, sizeof(int), 1, stream);
讀取後 stream 的讀取位置會移動,指向下筆資料。你可以看到 fread( ) 的參數以類似 qsort( ) 的方式描述一個陣列空間,所以也可以用來讀取多筆資料,例如一次讀入 3 個浮點數:
float vec[3]; int readBytes = fread(vec, sizeof(float), 3, stream); if (readBytes < 12) { printf("檔案結束!"); }
上例中的 fread( ) 應該讀取到 12 bytes,而且讀取後檔案讀取指標移動 12 bytes,如果不足12表示檔案已結束。你可以 ftell 來獲知目前的讀取位置,它傳回目前已讀取的長度(從檔案開頭算來幾 bytes)。
原型: long ftell( FILE * stream );
在結束讀取以後,你應該以 fclose( ) 關閉檔案,告訴作業系統這個檔案已經結束讀取或寫入了。
原型: int fclose( FILE * stream );
其中的參數 stream 是 fopen( ) 獲得的 FILE * 內部結構體指標,基本上,使用這種方式讀取檔案,你必須明確地知道該檔案的儲存格式,所以通常用於撰寫讀檔或解碼程式。
寫入二進位檔
FILE *stream = fopen("檔案名稱", "wb");
傳回一個內部結構體 FILE 的指標, "wb" 參數會建立一個空的新檔案,如果該檔案已經存在則會覆蓋掉它。若無法建立檔案(磁碟空間不足或唯讀)則傳回 NULL,如果不想要覆蓋掉原檔案,而是想要在原檔案尾端附加(append)資料,則以 "ab" 模式開啟檔案,但若原檔案不存在則會建立一個空的新檔案。
接著以類似 fread( ) 的方式呼叫 fwrite( ),寫入指定長度的資料到檔案中。
原型: size_t fwrite( void * buffer, size_t size, size_t count, FILE * stream );
參數
- buffer : 儲存欲寫入資料的記憶體空間。
- size : 寫入的單位長度,例如下例 sizeof(int)。
- count : 寫入的個數,下例只寫入1個整數。
- stream : fopen( ) 獲得的 FILE * 內部結構體指標。
傳回值
成功寫入的 bytes,如果發生錯誤(例如磁碟已滿)可能會少於 size*count bytes。
例如寫入一個整數:
fwrite(&a, sizeof(int), 1, stream);
完成檔案寫入以後,同樣必須以 fclose( ) 關閉檔案。
讀取文字檔案
同樣是以 fopen( ) 來開啟檔案,但是參數改用 "rt"。
開啟以後的檔案讀寫不使用 fread( ) 與 fwrite( ),而是類似前面的主控台輸出入,採用 fgetc( )、fgets( )、fputc( )、fputs( )、fprintf( ) 等等的字元或字串輸出入函式。
也可以把非文字檔當作文字檔開啟,但後續這些函式操作可能都會失敗。
FILE *stream =fopen("檔案名稱", “rt”);
傳回一個內部結構體 FILE 的指標,若無法開啟檔案(例如檔案不存在)則傳回 NULL。
讀取單一字元
原型: int fgetc( FILE * stream ); //是不是和 _getch( ) 很像?
例如: int c = fgetc(stream);
參數: stream : fopen( ) 獲得的 FILE * 內部結構體指標。
傳回值: 讀取到的字元,如果已經讀到檔尾則傳回 EOF,也就是整數 -1。
讀取一行字串
原型: char * fgets( char * str, int n, FILE * stream ); //是不是和 gets( ) 很像?
例如: fgetc(buffer, 512, stream);
參數
- str: 儲存讀取到的文字的字元陣列空間。
- n: str 的空間大小,避免 fgets( ) 讀取過頭。
- stream : fopen( ) 獲得的 FILE * 內部結構體指標。
傳回值
如果讀取不到一行文字則傳回 NULL。
#include <stdio.h> void main(void) { char buffer[256]; // 嘗試開啟 ReadMe.txt 檔案: FILE *stream = fopen("ReadMe.txt", "rt"); if (stream) { // 如果檔案開啟成功,以fgets( ) 逐行讀取: while(fgets(buffer, 256, stream) != NULL) { printf("%s\n", buffer); }
//fgets( ) 讀進來的文字不包含換行,所以顯示的時候特別以 printf 加 \n 來顯示之。 // 關閉檔案: fclose(stream); } else { printf("檔案不存在喔!"); } }
寫入文字檔
FILE *stream =fopen("檔案名稱", "wt");
傳回一個內部結構體 FILE 的指標。使用 "wt" 參數會建立一個空的新檔案,如果該檔案已經存在則會覆蓋掉它。使用 "at" 則從該檔案的尾端接著寫入,如果檔案不存在則會建立一個空的新檔案。若無法建立檔案(磁碟空間不足或唯讀)則會傳回 NULL。
單純寫入一串文字
原型: int fputs( const char* s, FILE* stream);// 是不是和 puts( ) 很像只是多了一個 stream 參數?
參數
- s: 待寫入的一行文字。
- stream : fopen( ) 獲得的 FILE * 內部結構體指標。
傳回值
如果寫入失敗則傳回 EOF。
格式化地寫入一串文字
原型: fprintf(FILE* stream,"" ,變數 );//紅色部分和一般printf一樣
二進位檔案操作是記憶體與檔案之間、逐 byte 的原始資料交換。
文字檔案的操作方法則是字串處理與輸出入。
從檔案中獲得的字串必須經過 strtok( ) 切割,atoi( ) 或 atof( ) 轉換為數值資料,才能夠進行運算。
重點整理
- 檔案的操作模式分為二進位和文字檔兩種。
- 檔案操作必須經過開啟檔案,讀寫檔案,關閉檔案的程序。
- 從主控台獲得字元或字串的方式,也有類似的方式從文字檔獲得字元或一行文字。
- 輸出文字到螢幕的方式,也有類似方式輸出文字到文字檔。
//補充函式
函數名稱 |
功能說明 |
fopen( ) |
開啟一個檔案//參數有很多種參考註 |
fclose( ) |
關閉一個檔案 |
putc( ) |
輸出一個字元到檔案 int putc( int ch, FILE *fp ); |
getc( ) |
從某一個檔案讀取一個字元 int getc(FILE *fp); |
fprintf( ) |
輸出資料至某檔案 |
fscanf( ) |
從某檔案讀取資料 //scanf( )函數主要用於從鍵盤輸入讀取資料,fscanf是從檔案讀取。 |
feof( ) |
測試是否到了檔案結束位置 |
ferror( ) |
測試檔案操作是否正常 |
fseek( ) |
設定準備讀取檔案資料的位置 |
rewind( ) |
將準備讀取檔案資料位置,設定在檔案起始位置 |
remove( ) |
檔案的刪除 |
註:
"r":開啟一個文字檔(text),供程式讀取。
"w":開啟一個文字檔(text),供程式將資料寫入此檔案內。如果磁碟內不包含這個檔案,則系統會自行建立。如果磁碟內包含這個檔案,則此檔案內容會被蓋過而消失。
"a":開啟一個文字檔(text),供程式將資料寫入此檔案的末端。如果此檔案不存在,則系統會自行建立此檔案。
"rb":開啟一個二元檔(binary),供程式讀取。
"wb":開啟一個二元檔,供程式將資料寫入此檔案內。如果磁碟內不包含這個檔案,則系統會自行建立這個檔案。如果磁碟內包含這個檔案,此檔案內容會被蓋過而消失。
"ab":開啟一個二元檔(binary),供程式將資料寫入此檔案末端,如果此檔案不存在,則系統會自行建立此檔案。
留言列表