1 / 41

Chapter 8

Chapter 8. 檔案處理 (File Processing). 什麼是檔案處理?. 當程式結束時,所有資料都會消失 「檔案」可以將資料永久保存於儲存硬體中 硬碟、軟碟、光碟、磁帶 … 為了資料的保存、及存取 檔案的處理是必要的 File 是由位元組成的循序資料流,以 EOF (end of file) 來結束 檔案被開啟後,資料流就會和檔案結合在一起. 開啟檔案 (1/2). FILE *fopen(const char * 檔案名稱 , const char * 模式 ). 開啟檔案 (2/2).

vesta
Download Presentation

Chapter 8

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Chapter 8 檔案處理 (File Processing)

  2. 什麼是檔案處理? • 當程式結束時,所有資料都會消失 • 「檔案」可以將資料永久保存於儲存硬體中 • 硬碟、軟碟、光碟、磁帶… • 為了資料的保存、及存取 • 檔案的處理是必要的 • File是由位元組成的循序資料流,以EOF (end of file)來結束 • 檔案被開啟後,資料流就會和檔案結合在一起

  3. 開啟檔案 (1/2) • FILE *fopen(const char *檔案名稱, const char *模式)

  4. 開啟檔案 (2/2) • 檔案開啟後會傳回一個指向FILE結構的指標,欲對該檔案執行動作,則對該指標執行 • b可以和其他模式並用,而且’+’的位置不影響其意義:w+b = wb+ • 當使用w+, r+, a+ 來存取檔案時,在讀、寫模式切換時要注意指標的位置 • fsetpos, fseek, rewind • fopen 若開檔成功,則會傳回指向FILE結構的指標,反之則傳回NULL • 開檔時,仍要檢查是否開啟成功

  5. 關閉檔案 • 檔案使用結束,或程式結束時必須將所開啟之檔案全部關閉 • 確保所有緩衝區軍備清除,且可以繼續使用,以及檔案能正確的關閉 • int fclose(FILE *stream) • 若關檔成功,則傳回0

  6. 開、關檔案範例 (1/2) #include <stdio.h> int main(void) { FILE *in; char filename[80], buff[80]; printf("Enter name of file to open: "); gets(filename); if((in = fopen(filename, "r")) == NULL){ //檢查開檔是否成功 printf("Error opening file: %s\n", filename); exit(0); } printf("==== Contents of input file ====\n"); while(fgets(buff, 80, in) != NULL){ printf("%s", buff); } fclose(in); //檔案用完後,關閉該檔案 return 0; }

  7. 開、關檔案範例 (2/2) Enter name of file to open: eha2.c ==== Contents of input file ==== HARRY POTTER AND THE CHAMBER OF SECRETS by J. K. Rowling (this is BOOK 2 in the Harry Potter series) Original Scanned/OCR: Friday, April 07, 2000 v1.0 (edit where needed, change version number by 0.1) C H A P T E RR O N E THE WORST BIRTHDAY … … …

  8. 讀取檔案資料 (1/2) • int fgetc(FILE *檔案指標); • 從檔案中以int的格式將字元一個一個的讀入 • size_t fread(void *buffer, size_t 型態單元大小, size_t 數目, FILE *檔案指標); • 通常用於二進位檔 (binary file),從檔案目前位置讀入某種型態的東西的緩衝區,讀完後檔案位置也會被更新 • char *fgets(char *buffer, int 數目, FILE *檔案指標); • 從檔案中讀入一字串,並存於緩衝區中 • 如遇到換行字元(\n),或是緩衝區大小少1,便會轉成字串,並在後面加上’\0’,’\n’也在字串中。 • 若成功則傳回字串,否則傳回NULL

  9. 讀取檔案資料 (2/2) • int fscanf(FILE *檔案, const char *格式, ...); • 依照所給的格式讀入資料,格式之指定以%開頭 (%d, %c, %s …) • 以%s為例:每當讀取到空白、Tab、換行時,便會視為動作結束 • 方便資料之處理,但要還原時困難(因為無法區隔空白、Tab、換行字元)

  10. 用fread()來改寫開、關檔案範例 (1/3) #include <stdio.h> int main(void) { FILE *in; char filename[80], buff[80]; int i; printf("Enter name of file to open: "); gets(filename); if((in = fopen(filename, "r")) == NULL){ //檢查開檔是否成功 printf("Error opening file: %s\n", filename); exit(0); } printf("==== Contents of input file ====\n"); while(fread(buff, sizeof(char), 80, in) != NULL){ printf("%s", buff); for(i = 0; i < 80; i++) buff[i] = 0;//為何要加這行 ? } fclose(in); //檔案用完後,關閉該檔案 return 0; }

  11. 用fread()來改寫開、關檔案範例 (2/3) Enter name of file to open: gcd.c ==== Contents of input file ==== #include <stdio.h> int gcd(int u, int v) { if(u < 0) u = -u; if(v < 0) v = -v; if(v == 0) return u; else return gcd(v, u%v); } int main(void) { int a, b, c; printf("Plz enter two non-zero number:"); scanf("%d %d", &a, &b); c = gcd(a, b); printf("gcd = %d\n", c); return 0; } scanf("%d %d", &a, &b); c = gcd //此版本沒有清buffer 在buffer中殘存的資料

  12. 用fread()來改寫開、關檔案範例 (3/3) Enter name of file to open: gcd.c ==== Contents of input file ==== #include <stdio.h> int gcd(int u, int v) { if(u < 0) u = -u; if(v < 0) v = -v; if(v == 0) return u; else return gcd(v, u%v); } int main(void) { int a, b, c; printf("Plz enter two non-zero number:"); scanf("%d %d", &a, &b); c = gcd(a, b); printf("gcd = %d\n", c); return 0; } //此版本有清buffer

  13. 用fgetc()來改寫開、關檔案範例 #include <stdio.h> int main(void) { FILE *in; char filename[80]; int i; printf("Enter name of file to open: "); gets(filename); if((in = fopen(filename, "r")) == NULL){ printf("Error opening file: %s\n", filename); exit(0); } printf("==== Contents of input file ====\n"); do{ i = fgetc(in); // 用法與getc()類似 printf("%c", i); }while(i != EOF); fclose(in); return 0; }

  14. 用fscanf()來改寫開、關檔案範例 (1/2) #include <stdio.h> int main(void) { FILE *in; char filename[80], buff[81]; printf("Enter name of file to open: "); gets(filename); if((in = fopen(filename, "r")) == NULL){ printf("Error opening file: %s\n", filename); exit(0); } printf("==== Contents of input file ====\n"); while(fscanf(in, "%s", buff) != EOF){ printf("%s\n", buff); } fclose(in); return 0; } 用來區隔每次抓到的字串

  15. 用fscanf()來改寫開、關檔案範例 (2/2) Enter name of file to open: gcd.c ==== Contents of input file ==== #include <stdio.h> int gcd(int u, int v) { if(u < 0) u = -u; ... ... ...

  16. 寫資料到檔案(1/2) • int fputc(int欲寫入字元, FILE *檔案); • 將字元(int)寫入檔案,寫入後檔案指標位置會增加 • size_t fwrite(const void *欲寫入字串, size_t 型態單元大小, size_t 數目, FILE *檔案指標); • 通常用於二進位檔 (binary file),從緩衝區寫入某種型態的東西到檔案目前位置,寫完後檔案位置也會被更新 • int fputs(const char *s, FILE *stream); • 將存於緩衝區中一字串寫入檔案 • 若成功則傳回最後一個被寫入的字元,否則傳回EOF

  17. 寫資料到檔案(2/2) • int fprintf(FILE *檔案, const char *格式, /* args*/ ...); • 和printf一樣,可以接受的參數個數並不一定,而不同的是這些參數要輸出指定的檔案 • 當所要輸入、輸出的檔案為stdin、stdout時,可以視為對標準輸入輸出做讀寫動作

  18. Copy範例 (fgets(), fputs() – 1) #include <stdio.h> int main(void) { FILE *in, *out; char infile[80], outfile[80], buff[80]; printf("Enter name of file to open: "); gets(infile); //抓輸入檔案檔名 printf("Enter name of file to write: "); gets(outfile); //抓輸出檔案檔名 if((in = fopen(infile, “r”)) == NULL){ //檢查檔案是否可開成可讀 printf("Error opening file: %s\n", infile); exit(0); } if((out = fopen(outfile, “w”)) == NULL){ //檢查檔案是否可開成可寫 printf("Error opening file: %s\n", outfile); exit(0);

  19. Copy範例 (fgets(), fputs() – 1) } while(fgets(buff, 80, in) != NULL){ fputs(buff, out); //把從輸入檔案抓到的資料寫到輸出檔 } fclose(in); //關閉檔案 fclose(out); return 0; }

  20. fgets(), fputs() 與 stdin, stdout #include <stdio.h> //字串反轉範例 #include <string.h> int main(void) { char str[80], revstr[80]; int i = 0, j; printf("Please enter a string: "); fgets(str, 80, stdin); //對標準輸入抓值 j = strlen(str); while(str[i]){ revstr[j - i] = str[i]; i++; } revstr[j+1] = '\0'; fputs(revstr, stdout); //對標準輸出寫值 return 0; }

  21. fgets/fputs 跟 gets/puts 的差別 • fgets 會檢查 buffer 的大小,所以不會產生 buffer overflow • gets 不會檢查 buffer 的大小,讀取時要確定 buffer 夠大 • gets 若遇到換行符號,會結束讀取,但不會把換行符號儲存到 buffer 裡面 • fgets 會把換行符號寫入 buffer • puts 在輸出時,會自己加上換行符號 • fputs 則無此特性

  22. scanf 家族的格式化字串 • 可以包含下面三種 • 空白字元(Whitespace): 一個或者一個以上的輸入空白字元會被忽略 • 轉換指定詞: 用來解釋輸入的資料為那種型態 • 可以有四個欄位 • 星號: 代表轉換後的資料會被丟掉 • 寬度: 非負整數值,可以限制輸入的字元數;如果沒設定這個欄位,scanf 會一直讀取,直到遇到空白字元為止 • 修飾詞(Qualifier): h,l,L 用來修飾整數大小 • 轉換指定詞 : d,i,n, o,u,x, e,f,g • 其他字元: 其他字元若出現在格式化字串裡面,則輸入的資料必須跟這些字元吻合,scanf 函式才會進行轉換並且讀取的動作

  23. scanf 轉換指定詞 (Conversion Specifiers)

  24. fscanf & scanf 的範例 /* fscanf 的範例 */ #include <stdio.h> void main() { int a, b, c; if(fscanf(stdin, "%d %d", &a, &b) == 2 ) printf("已讀取到 2 個整數: %d, %d\n",a,b); fflush(stdin); if(scanf("%4d %4d %4d", &a, &b, &c)== 3) printf("讀取到 3 個整數:%d %d %d\n", a,b,c); } 執行結果: 12345 67890 已讀取到 2 個整數: 12345, 67890 12345 67890 讀取到 3 個整數:1234 5 6789

  25. scan set 的運用 /* scan set 的範例 */ #include <stdio.h> void main() { char string[255]="test"; printf("請輸入字串 :"); scanf("%[aeiou]", string); printf("讀到 %s\n",string); fflush(stdin); printf("請輸入字串 :"); scanf("%[^aeiou]", string); printf("讀到 %s\n", string); } 執行結果: 請輸入字串 :aaaabbbbb 讀到 aaaa 請輸入字串 :bbbbcccaaa 讀到 bbbbccc

  26. 禁止字元的運用 /* *(禁止字元)用在 scanf 的範例 */ #include <stdio.h> void main() { int month, day, year; printf("請輸入日期(年/月/日) :"); scanf("%d%*c%d%*c%d", &year, &month, &day); printf("你輸入的是:\n"); printf("%d年%d月%d日 \n", year, month, day); } 執行結果: 請輸入日期(年/月/日) :2002-12-24 你輸入的是: 2002年12月24日 請輸入日期(年/月/日) :2002/12-24 你輸入的是: 2002年12月24日

  27. printf 家族的格式化字串 • 可以包含下面五種 • flag: 控制格式化字串的轉換方式 • 最小列印欄位: 用來控制輸出的最小欄位 • 精準度: 用來控制小數的位數 • 修飾詞: (h,l,L)用來修飾轉換指定詞 • 轉換指定詞:

  28. printf 家族的旗標 (flag)

  29. printf 家族轉換指定詞

  30. 簡單的範例 (1/4)

  31. 簡單的範例 (2/4)

  32. 簡單的範例 (3/4)

  33. 簡單的範例 (4/4)

  34. 矩陣相乘檔案版 (1/7) #include <stdio.h> #include <stdlib.h> #include <ctype.h> int main(int argc, char *argv[]) { FILE *in1, *in2, *out; char file1[20], file2[20], file3[20], buff[20]; int i, j, k, m, n, l; int **matrix1, **matrix2, **matrix3, *row; if(argc != 5){ //判別傳入引數個數是否正確 printf("%s 是矩陣[m, n]和[n, l]相乘的運算\n", argv[0]); printf("輸入變數不足\n"); printf("Usage: %s m n n l\n", argv[0]); exit(0); }

  35. 矩陣相乘檔案版 (2/7) else if(strcmp(argv[2], argv[3])){ //檢查矩陣的維數是否合法 printf("%s 是矩陣[m, n]和[n, l]相乘的運算\n", argv[0]); printf("你輸入的矩陣維數不合法\n"); printf("Usage: %s m n n l\n", argv[0]); exit(0); } else{ //檢查輸入維數是否全部為數字 for(i = 1; i < 5; i++){ j = 0; while(argv[i][j] != '\0'){ if(!isdigit((int) argv[i][j])){ printf("%s is not a digit\n", argv[i]); exit(0); } j++; } } }

  36. 矩陣相乘檔案版 (3/7) m = atoi(argv[1]); n = atoi(argv[2]); l = atoi(argv[4]); printf(“請輸入第一個矩陣檔案:”); //輸入矩陣所在的檔案名稱 gets(file1); printf("請輸入第二個矩陣檔案:"); gets(file2); printf("請輸入第輸出矩陣檔案:"); gets(file3); if((in1 = fopen(file1, “r”)) == NULL){ //開啟檔案並且測試是否成功 printf("第一個矩陣檔案無法開啟\n"); exit(0); } if((in2 = fopen(file2, "r")) == NULL){ printf("第二個矩陣檔案無法開啟\n"); exit(0); } if((out = fopen(file3, "w")) == NULL){

  37. 矩陣相乘檔案版 (4/7) printf("輸出矩陣檔案無法開啟\n"); exit(0); } if((matrix1=(int **)malloc(sizeof(int *) *m) ) == NULL){ printf(“malloc 1 fail\n”); //要動態記憶體並且檢查 exit(0); } if((matrix2=(int **)malloc(sizeof(int *) *n) ) == NULL){ printf("malloc 2 fail\n"); exit(0); } if((matrix3=(int **)malloc(sizeof(int *) *m) ) == NULL){ printf("malloc 3 fail\n"); exit(0); } //get matrix 1 for(i = 0; i < m; i++){ //抓第一個矩陣的值 if((row=(int *)malloc(sizeof(int) *n) ) == NULL){

  38. 矩陣相乘檔案版 (5/7) printf("In matrix 1: %d row is not available\n", i); exit(0); } for(j = 0; j < n; j++){ fscanf(in1, "%s", buff); row[j] = atoi(buff); } matrix1[i] = row; } //get matrix 2 for(i = 0; i < n; i++){ //抓第二個矩陣的值 if((row=(int *)malloc(sizeof(int) *l) ) == NULL){ printf("In matrix 2: %d row is not available\n", i); exit(0); } for(j = 0; j < n; j++){ fscanf(in2, "%s", buff); row[j] = atoi(buff);

  39. 矩陣相乘檔案版 (6/7) } matrix2[i] = row; } //calculate matrix 3 for(i = 0; i < m; i++){ //要矩陣記憶體,並且計算矩陣值 if((row=(int *)calloc(l, sizeof(int)) ) == NULL){ printf("In matrix 3: %d row is not available\n", i); exit(0); } matrix3[i] = row; for(j = 0; j < l; j++) for(k = 0; k < n; k++) matrix3[i][j] += matrix1[i][k]*matrix2[k][j]; } for(i = 0; i < m; i++){ //把算完的值寫入檔案 for(j = 0; j < l; j++) fprintf(out, "%d ", matrix3[i][j]); fprintf(out, "\n");

  40. 矩陣相乘檔案版 (7/7) } //歸還所要的記憶體 for(i = 0; i < m; i++) free(matrix1[i]); for(i = 0; i < n; i++) free(matrix2[i]); for(i = 0; i < m; i++) free(matrix3[i]); free(matrix1); free(matrix2); free(matrix3); //關閉所開啟的檔案 fclose(in1); fclose(in2); fclose(out); return 0; }

  41. 檔案讀、寫注意事項 • 檔案的讀跟寫有很多函式可應用 • 依據需要選擇適當的函式 • 二進位檔:fread(), fwrite() • 一般文字檔: fgets(), fputs() • 字元:fgetc(), fputc() • 抓單字(word):fscanf(), fprintf()

More Related