檔案的輸入 輸出 12-1 輸入 輸出的基礎 理解資料流 (stream) 的概念 在 C 語言中支援各種輸出入功能的概念, 就稱為資料流 執行附加格式的輸入 輸出 printf() 和 scanf() 是用來輸出 輸入的函數 必須先引入 stdio.h 檔案才能使用這些函數 這兩個函數會以固定的格式進行輸出入, 也可以使用各種不同的轉換規格
使用固定格式的輸出 輸入函數之範例 : int main(void) int i; double d; char str[100]; printf(" 請輸入一個整數 \n"); scanf("%d", &i); printf(" 請輸入一個小數 \n"); scanf("%lf", &d); printf(" 請輸入一個字串 \n"); scanf("%s", str); scanf() 函數執行固定格式的輸入 printf() 函數執行固定格式的輸出 printf(" 所輸入的整數為 %d \n", i); printf(" 所輸入的小數為 %lf \n", d); printf(" 所輸入的字串為 %s \n", str);
表 12-1:printf() 函數的轉換規格 轉換規格 內容 %c 以字元輸出 %d 以 10 進制輸出 %f 以浮點小數輸出 %e 以科學記號表示法, 指數部分加上 (e) 之後輸出 %E 以科學記號表示法, 指數部分加上 (E) 之後輸出 %s 以字串輸出 %p 以指標輸出 %o 以 8 進制輸出 %x 以 16 進制 ( 小寫 ) 輸出 %X 以 16 進制 ( 大寫 ) 輸出 %u 以不帶記號的 10 進制輸出
表 12-2:scanf() 函數的轉換規格 轉換規格 內容 %c 以字元輸入 %d 以 10 進制輸入 %f 以浮點小數 (float 型態 ) 輸入 %lf 以浮點小數 (double 型態 ) 輸入 %s 以字串輸入 %p 以指標輸入 %o 以 8 進制輸入 %x 以 16 進制輸入 %u 以不帶記號的 10 進制輸出
指定輸出寬度 要指定輸出寬度的時候, 將數值指定給轉換規格 要指定輸出位置的話, 將 + 或是 - 指定給轉換規格 範例 : int main(void) int i; for (i=1; i<=10; i++) printf("%3d", i); printf("\n"); 以三個字元的寬度間隔輸出 10 進制整數
指定精度 要指定精度的時候, 要在逗點 (.) 的後面指定數值 範例 : int main(void) double num; 以小數點以下三位數輸出 printf(" 請輸入小數 \n"); scanf("%lf", &num); printf(" 如果輸出小數點以下 3 位的話, 就變成 %.3f \n", num); 將轉換規格組合起來 輸出格式的指定之語法 : %± 輸出寬度. 精度格式
以 10 進制以外的方式輸出 用各種表示方法進行輸出之範例 : int main(void) 以 8 進制來輸出 printf(" 如果把 10 用 10 進制來表示的話, 就變成 %d \n", 10); printf(" 如果把 10 用 8 進制來表示的話, 就變成 %o \n", 10); printf(" 如果把 12 用 10 進制來表示的話, 就變成 %o \n", 12); printf(" 如果把 10 用 16 進制來表示的話, 就變成 %x \n", 10); 以 16 進制來輸出 用 10 進制進行輸出的轉換規格為 %d 用 8 進制進行輸出的轉換規格為 %o 用 16 進制進行輸出的轉換規格為 %x
12-2 各種輸出 輸入函數 單行的輸出 輸入 由於使用 scanf() 函數來輸入字串時, 會無法儲存空白的部份, 所以必須使用其他輸入函數 gets() 函數可進行單行輸入 puts() 函數可進行單行輸出 單一字元的輸入 輸出 putchar() 函數可進行單一字元的輸出 getchar() 函數可進行單一字元的輸入
12-3 檔案輸出 輸入的基礎 檔案的機制 檔案操作的步驟為 : 1. 開啟 2. 讀取寫入 3. 關閉
檔案操作的範例 : int main(void) 檔案指標 FILE *fp; fp = fopen("test1.txt", "w"); if(fp == NULL) printf(" 無法開啟檔案 \n"); return 1; else printf(" 檔案開啟 \n"); fclose(fp); printf(" 檔案關閉 \n"); 指定檔案名稱指定開啟模式當無法開啟的時候, 進行錯誤處理將檔案關閉
檔案的開啟和關閉 fopen() 函數 fclose() 函數之語法 : FILE * 檔案指標 = fopen(" 檔案名稱 ", 開啟模式 ); fclose( 檔案指標 ); 開啟模式 意義 "w" 用於寫入使用, 開啟純文字檔案 "r" 用於讀取使用, 開啟純文字檔案 "a" 用於追加寫入使用, 開啟純文字檔案 "w+" 用於更新使用, 開啟純文字檔案 ( 建立新檔案 ) "r+" 用於更新使用, 開啟純文字檔案 ( 開啟檔案 ) "a+" 用於更新 追加寫入使用, 開啟純文字檔案 "wb" 用於寫入使用, 開啟 2 位元檔案 "rb" 用於讀取使用, 開啟 2 位元檔案 "ab" 用於追加寫入使用, 開啟 2 位元檔案
將單一行輸出至檔案 要寫入一行資料到純文字檔案的時候, 要使用 fputs() 函數 範例 : int main(void) FILE *fp; fp = fopen("test1.txt", "w"); if(fp == NULL) printf(" 無法開啟檔案 \n"); return 1; else printf(" 開啟檔案 \n"); fputs("hello!\n", fp); fputs("goodbye!\n", fp); printf(" 寫入至檔案 \n"); fclose(fp); printf(" 關閉檔案 \n"); 輸出至檔案
以固定格式輸出至檔案 要使用指定格式寫入資料至純文字檔案時, 要使用 fprintf() 函數 範例 : #define NUM 5 int main(void) FILE *fp; int test[num]; int i, j; fp = fopen("test2.txt", "w"); if(fp == NULL) printf(" 無法開啟檔案 \n"); return 1; else printf(" 檔案開啟 \n"); printf(" 請輸入 %d 人的成績 \n", NUM); for(i=0; i<num; i++) scanf("%d",&test[i]); for(j=0; j<num; j++) fprintf(fp, "No.%-5d%d\n", j+1, test[j]); printf(" 寫入至檔案 \n"); fclose(fp); printf(" 檔案關閉 \n"); 加上格式之後輸出至檔案中
由檔案輸入一行資料 要從純文字檔案讀取單行資料時, 可以使用 fgets() 函數 範例 : #define NUM 20 int main(void) FILE *fp; char str1[num]; char str2[num]; fp = fopen("test1.txt", "r"); if(fp == NULL) printf(" 無法開啟檔案 \n"); return 1; else printf(" 檔案開啟 \n"); fgets(str1, NUM-1, fp); fgets(str2, NUM-1, fp); printf(" 寫入至檔案的字串為 :\n"); printf("%s", str1); printf("%s", str2); fclose(fp); printf(" 檔案關閉 \n"); 以讀取模式開啟檔案 從指定檔案把最大 NUM-1 個的字元儲存至 str1 來作為字串
輸入大量的資料 如果要從純文字檔案中以固定格式讀取資料的話, 可以使用 fscanf() 函數 範例 : #define NUM 8 int main(void) FILE *fp; int test[num]; int max, min; int i, j; fp = fopen("test3.txt", "r"); if(fp == NULL) printf(" 無法開啟檔案 \n"); return 1; for(i=0; i<num; i++) fscanf(fp, "%d", &test[i]); max = test[0]; min = test[0]; for(j=0; j<num; j++) if(max < test[j]) max = test[j]; if(min > test[j]) min = test[j]; printf("no.%-5d%d\n", j+1, test[j]); printf(" 最高分為 %d \n", max); printf(" 最低分為 %d \n", min); fclose(fp); 求出最高分和最低分
12-4 二進位檔與隨機存取 寫入資料至二進位檔 要寫入指定大小的資料時, 可以使用 fwrite() 函數 fwrite() 函數之語法 : fwrite( 指向寫入資料的指標, 資料大小, 個數, 檔案指標 ); 範例 : #define NUM 5 int main(void) FILE *fp; int test[num] = 80,60,22,50,75; int i; fp = fopen("test1.bin", "wb"); if(fp == NULL) printf(" 無法開啟檔案 \n"); return 1; for(i=0; i<num; i++) fwrite(&test[i], sizeof(int), 1, fp); printf(" 寫入檔案 \n"); fclose(fp); 將二進位檔開啟為寫入模式 將陣列的各元素輸出至檔案
讀取二進位檔 要讀取指定大小的資料, 可以使用 fread() 函數 fread() 函數 fread( 指向讀取範圍的指標, 資料大小, 個數, 檔案指標 ); 範例 : #define NUM 5 int main(void) FILE *fp; int test[num]; int i, j; fp = fopen("test1.bin", "rb"); if(fp == NULL) printf(" 無法開啟檔案 \n"); return 1; for(i=0; i<num; i++) fread(&test[i], sizeof(int), 1, fp); for(j=0; j<num; j++) printf("%d\n", test[j]); fclose(fp); 以讀取模式開啟二進位檔
隨機存取 由檔案的最前面開始依照順序進行讀寫的方法稱之為 循序存取 由檔案的任意地方開始讀寫的方法稱之為 隨機存取 fseek() 函數之語法 : fseek( 檔案指標, 要移動的大小, 開始位置 ); fseek() 函數可以使用的巨集 SEEK_SET 檔案的最前面 SEEK_CUR 現在位置 SEEK_END 檔案的最後
進行隨機存取之範例 : #define NUM 5 int main(void) FILE *fp; int num; int i; fp = fopen("test1.bin", "rb"); if(fp == NULL) printf(" 無法開啟檔案 \n"); return 1; printf(" 要讀取第幾號資料?(1~5)\n"); scanf("%d", &i); fseek(fp, (i-1)*sizeof(int), SEEK_SET); fread(&num, sizeof(int), 1, fp); printf(" 第 %d 號的資料為 %d \n", i, num); fclose(fp); 移動到讀取的位置
12-5 由指令列進行輸入 使用指令列引數 指令列引數之語法 : int main(int argc, char *argv[]) 接受輸入字串的個數 接受輸入的字串 當輸入以下資料時 : Sample1 myfile.txt argc 為 2 argv[0] 為 Sample1 argv[1] 為 myfile.txt
使用指令列引數之範例 : int main(int argc, char *argv[]) FILE *fp; int ch; if(argc!= 2) printf(" 參數的數目不同 \n"); return 1; fp = fopen(argv[1], "r"); if(fp == NULL) printf(" 無法開啟檔案 \n"); return 1; while((ch = fgetc(fp))!= EOF) putchar(ch); fclose(fp); 查詢輸入字串的個數 指定輸入的第二個字串並開啟檔案 將字元逐一讀取出來, 直到檔案的最後
12-6 程式除錯 理解除錯的機制 程式中的錯誤叫做臭蟲 (bug) 除去臭蟲的作業叫做除錯 (debug) 理解附加條件的編譯方式 C 語言的前置處理器可以指定所依照之條件, 來進行程式編譯 這就稱為附加條件的編譯方式 (conditional compilation)
附加條件的編譯方式之範例 : #define DEBUG int main(void) int i; int sum = 0; 定義巨集 當巨集已經定義好的時候 for(i=1; i<=5; i++) #ifdef DEBUG fprintf(stderr, " 變數 sum 的值為 %d \n", sum); #endif sum = i + sum; 編譯這段程式 printf("1~5 為止的合計值為 %d \n", sum);
附加條件的編譯方式 (#ifdef) #ifdef 巨集程式敘述 ; #endif 附加條件的編譯方式 (#ifndef) #ifndef 巨集程式敘述 ; #endif 附加條件的編譯方式 (#if) #if 運算式 1 程式敘述 ; #elif 運算式 2 程式敘述 ; #else 程式敘述 ; #endif 使用內建的巨集 表 12-4: 內建的巨集 巨集名稱 置換的內容 LINE 原始碼檔案的行號 FILE 原始碼檔案的檔案名稱 DATE 原始碼檔案的編譯日期 TIME 原始碼檔案的編譯時間 TIMESTAMP 原始碼檔案的最後更動時間 STDC 如果對應 ANSI C 的話, 則為 1