370 likes | 501 Views
CH-10. 檔案處理 V2. 檔案觀念. 「 檔案 」( Files )是儲存在電腦周邊裝置的位元組資料集合,通常是儲存在軟硬磁碟機的資料,程式可以將輸出的資料儲存在檔案中保存,或是將檔案視為輸入資料讀取檔案內容,檔案的位元組資料可能被解譯成字元、數值、整數、字串或資料庫的記錄,取決於程式開啟的檔案存取類型。 C 語言標準函式庫的「檔案 I/O 」( File Input/Output )函數可以處理二種檔案類型: 文字和二進位檔案 。. 文字檔案.
E N D
CH-10 檔案處理 V2
檔案觀念 • 「檔案」(Files)是儲存在電腦周邊裝置的位元組資料集合,通常是儲存在軟硬磁碟機的資料,程式可以將輸出的資料儲存在檔案中保存,或是將檔案視為輸入資料讀取檔案內容,檔案的位元組資料可能被解譯成字元、數值、整數、字串或資料庫的記錄,取決於程式開啟的檔案存取類型。 • C語言標準函式庫的「檔案I/O」(File Input/Output)函數可以處理二種檔案類型:文字和二進位檔案。
文字檔案 • 文字檔案儲存的是字元資料,文字檔案視為一種「文字串流」(Text Stream),串流可以想像成水龍頭流出的是一個個字元,也就是說處理文字檔案只能向前一個個循序處理字元,也稱為「循序檔案」(Squential Files),如同水往低處流,並不能回頭處理之前處理過的字元。 • 文字檔案的處理 • 讀取(Input) • 寫入(Output) • 新增(Append)(如同輸出)
文字檔案的讀寫 • 開啟與關閉文字檔案 • 讀寫字串到文字檔案 • 讀寫字元到文字檔案 • 格式化讀寫文字檔案
開檔與關檔 • 開檔 • FILE *fopen(char *filename, char *mode) • FILE *fp; • fp = fopen(“aa.txt”, “r”); • fp = fopen(“bb.txt”,”w”); • fp = fopen(“cc.txt”,”a”); • 關檔 • int fclose(FILE *fp); • fclose(fp);
File mode • r • w • a • r+ • w+ • a+
檢查檔案是否開啟 if ( fp == NULL ) { printf("檔案開啟失敗....\n"); exit(1); }
從文字檔案讀寫字串 • intfputs(char *str,FILE *fp); • fputs(line , fp); /* 寫入字串 */ • char *fgets(char *str, int num, FILE *fp ) • fgets(line, 50 ,fp); /* 讀出字串*/
讀取整個檔案內容 While ( fgets(line, 50 ,fp) != NULL ) { ………………… }
從文字檔案讀寫字元 • int putc(int ch , FILE *fp); • putc(line[j] , fp); /* 寫入字元 */ • chargetc(FILE *fp); • c =getc(fp); /* 讀出字元 */ while ((c = getc(fp)) != EOF ) putchar(c);
格式化讀寫 • int fprintf(FILE *fp, char * control , …..); • fprintf(fp, "%d: %s\n", i+1, line); • intfscanf(FILE *fp, char * control , …..); • fscanf(fp,"%s", line );
開關檔範例 #include <stdio.h> #include <stdlib.h> main(int argc, char *argv[]) { FILE *fp; if ( argc <= 2 ) { printf("使用: Ch10-2-1.exe filename mode\n"); exit(1); /* 錯誤, 結束程式 */ } fp = fopen(argv[1], argv[2]); if ( fp == NULL ) { /* 檔案開啟失敗 */ printf("檔案[%s]開啟失敗....\n", argv[1]); exit(1); /* 錯誤, 結束程式 */ } else { printf("開啟檔案:[%s]\n", argv[1]); printf("檔案模式:[%s]\n", argv[2]); } fclose(fp); /* 關閉檔案 */ }
讀寫字串範例 #include <stdio.h> main() { FILE *fp; char filename[20] = "../bb.txt"; char line[50] = "KSU ELE\n"; char *c; int i, count; fp = fopen(filename, "w"); printf("開始寫入檔案%s....\n", filename); for ( i = 0; i < 5; i++) fputs(line , fp); /* 寫入字串 */ printf("寫入檔案結束!\n"); fclose(fp); /* 關閉檔案 */ fp = fopen(filename, "r"); if ( fp != NULL ) { count = 0; while( fgets(line, 50 ,fp) != NULL ) { printf("%s", line); /* 顯示文字內容 */ count++; } printf("一共讀取%d行文字內容\n", count); fclose(fp); /* 關閉檔案 */ } else printf("檔案開啟錯誤...\n"); getchar(); }
讀寫字元範例 #include <stdio.h> main() { FILE *fp; char filename[20] = "../bb.txt"; char line[50] = "崑山科技大學\n"; char c; int i, j; fp = fopen(filename, "a"); printf("開始寫入檔案%s....\n", filename); for ( i = 0; i < 5; i++) for ( j = 0; line[j] != '\0'; j++ ) putc(line[j] , fp); /* 寫入字元 */ printf("寫入檔案結束!\n"); fclose(fp); /* 關閉檔案 */ fp = fopen(filename, "r"); if ( fp != NULL ) { /* 讀取檔案 */ while ((c = getc(fp))!= EOF ) putchar(c); fclose(fp); /* 關閉檔案 */ } else printf("檔案開啟錯誤...\n"); getchar(); }
格式化讀寫範例 #include <stdio.h> main() { FILE *fp; char filename[20] = "../bb.txt"; char line[50] = "我愛C語言"; int i; char c; fp = fopen(filename, "w"); printf("開始寫入檔案%s....\n", filename); for ( i = 0; i < 5; i++) /* 格式化輸出 */ fprintf(fp, "%d: %s\n", i+1, line); printf("寫入檔案結束!\n"); fclose(fp); /* 關閉檔案 */ fp = fopen(filename, "r"); if ( fp != NULL ) { /* 讀取檔案 */ while ( fscanf(fp,"%s", line) != EOF ) printf("%s\n", line); fclose(fp); /* 關閉檔案 */ } else printf("檔案開啟錯誤...\n"); getchar(); }
產生5個亂數,寫至test1_982.txt //產生5個亂數,介於5至100之間,寫至test1_982.txt ex10.c #include <stdio.h> #include <stdlib.h> #include <time.h> #define random( x) rand() % x void main(int argc, char *argv[]) { int i,j; int a[5]; char buf[10]; FILE *fp; fp = fopen("test1_982.txt","w"); srand(time(NULL) % 50); for (i=0; i < 5 ; i++) { a[i] = 1 + random(100 - 5 + 1 ); printf("%d ", a[i]); itoa(a[i],buf,10); //整數變字串 fputs(buf,fp); fputs("\n",fp); } fclose(fp); }
產生5個亂數,寫至test2_982.txt //產生5個亂數,介於5至100之間,寫至test2_982.txt ex11.c #include <stdio.h> #include <stdlib.h> #include <time.h> #define random( x) rand() % x void main(int argc, char *argv[]) { int i,j; int a[5]; FILE *fp; fp = fopen("test2_982.txt","w"); srand(time(NULL) % 50); for (i=0; i < 5 ; i++) { a[i] = 1 + random(100 - 5 + 1 ); printf("%5d\n", a[i]); fprintf(fp,“%5d\n”,a[i]); //重點 } fclose(fp); getch(); }
輸入5個字串寫至檔案 //輸入5個字串,寫至test3_982.txt ex12.c #include <stdio.h> void main(int argc, char *argv[]) { int i; char buf[50]; FILE *fp; fp = fopen("test3_982.txt","w"); for (i=0; i < 5 ; i++) { gets(buf); fputs(buf , fp); /* 寫入字串 */ putc('\n' , fp); } fclose(fp); getch(); }
顯示檔案內容 //顯示檔案內容,test3_982.txt ex12.c #include <stdio.h> void main(int argc, char *argv[]) { int i; char buf[50]; FILE *fp; fp = fopen("test3_982.txt","r"); while( fgets(buf, 50 ,fp) != NULL ) printf("%s", buf); /* 顯示文字內容 */ fclose(fp); getch(); }
統計字母個數 //統計字母個數,test3_982.txt ex14.c #include <stdio.h> void main(int argc, char *argv[]) { int i,s=0; char buf[50]; FILE *fp; fp = fopen("test3_982.txt","r"); while( fgets(buf, 50 ,fp) != NULL ) { printf("%s", buf); /* 顯示文字內容 */ s += count_letter(buf); } fclose(fp); printf("\n 字母共有%d個",s); getch(); }
統計字母個數2 int count_letter(char *p) { int c=0; while ( *p ) { if ( islower(*p) ) c++; p++; } return c; }
二進位檔案 • 沒有處理過的「位元組」(Bytes)資料 • 二進位檔案可以依需求以循序或「隨機存取」(Random Access)方式進行處理,隨機處理可以將檔案視為一個儲存在記憶體的陣列或結構陣列,只需移動「檔案指標」(File Pointer)到存取的位置,就可以存取資料,如同在陣列使用索引存取陣列元素。
二進位檔案的讀寫 • 二進位檔案讀寫除了可以使用文字檔案的循序方式存取,還可以使用隨機方式,以記錄為單位進行存取,能夠隨機存取任一筆記錄或更改指定記錄的資料。
二進位檔案的讀寫 FILE *fp; fp = fopen("filename", "wb");
開啟模式 • rb • wb • r+b • w+b
結構 • 隨機存取是以記錄為存取單位,在建立二進位檔案的隨機存取前,C程式需要宣告結構來儲存資料,例如:學生資料的record結構,如下所示: struct record { char name[20]; int age; float score; }; typedef struct recordstudent;
二進位檔案-相關函數 /* 開啟檔案新增內容 */ fp = fopen(filename, "r+b"); /* 寫入檔案 */ fwrite(&std, sizeof(std), 1, fp); /* 搜尋指定記錄的檔案指標位置 */ fseek(fp, rec*sizeof(std) , SEEK_SET); /* 讀取檔案 */ result = fread(&std, sizeof(std), 1, fp); /* 輸出緩衝區 */ fflush(fp); /* 關閉檔案 */ fclose(fp);
feof()函數 • feof()函數是用來檢查是否讀到檔尾 while ( !feof(fp) ) { …………… }
fseek()函數 • fseek()函數的offset參數是位移量,可以使用記錄數和結構大小計算而得,如下所示: fseek(fp, rec*sizeof(std), SEEK_SET); • 程式碼是從SEEK_SET位置的檔案開頭開始,位移量是rec*sizeof(std)位元組數,其中rec是記錄編號從0開始,使用sizeof運算子計算結構大小,即記錄尺寸,origin參數值有三種,如下: • SEEK_SET:從檔案開頭。 • SEEK_CUR:從檔案現在的位置。 • SEEK_END:從檔案結尾。
寫入記錄到二進位檔(ex06) #include <stdio.h> #include <string.h> struct record { char name[20]; int age; float score; }; typedef struct record student; void addrecord(FILE *, char *, int, int); main() { FILE *fp; student std; char filename[20] = "ex06.dat"; fp = fopen(filename, "wb"); printf("開始寫入檔案%s....\n", filename); addrecord(fp, "陳小安", 22, 65.5); addrecord(fp, "江小魚", 21, 78.9); addrecord(fp, "張無忌", 20, 67.8); printf("已經寫入3筆記錄!\n"); fclose(fp); /* 關閉檔案 */ getchar(); }
寫入記錄到二進位檔(ex06)2 void addrecord(FILE *fp, char *name, int age, int score) { student temp; /* 指定結構的成員變數 */ strcpy(temp.name, name); temp.age = age; temp.score = score; /* 寫入檔案 */ fwrite(&temp, sizeof(temp), 1, fp); }
循序讀取檔案的記錄(ex07) #include <stdio.h> struct record { char name[20]; int age; float score; }; typedef struct record student; main() { FILE *fp; student std; char filename[20] = "../ex06.dat"; fp = fopen(filename, "rb"); if ( fp != NULL ) /* 檢查是否有錯誤 */ { while ( !feof(fp) ) /* 是否是檔尾 */ { if ( fread(&std, sizeof(std), 1, fp) ) { /* 顯示記錄資料 */ printf("姓名: %s\n", std.name); printf("年齡: %d\n", std.age); printf("成績: %6.2f\n", std.score); printf("--------------------\n"); } } fclose(fp); /* 關閉檔案 */ } else printf("檔案開啟錯誤...\n"); getchar(); }
隨機讀取檔案範例(ex05) #include <stdio.h> #include <stdlib.h> struct record { char name[20]; int age; float score; }; typedef struct record student; main() { FILE *fp; student std; int rec, result, doedit; float score; char filename[20] = "../ex06.dat"; fp = fopen(filename, "r+b"); if ( fp == NULL ) /* 檢查是否有錯誤 */ { printf("檔案開啟錯誤...\n"); exit(1); }
隨機讀取2 printf("請輸入記錄編號[0-2]? "); scanf("%d", &rec); while ( rec >= 0 ) { fseek(fp, rec*sizeof(std), SEEK_SET); printf("目前的檔案位置: %ld\n", ftell(fp)); result = fread(&std, sizeof(std), 1, fp); if (result==1) { /* 顯示記錄資料 */ printf("--------------------\n"); printf("姓名: %s\n", std.name); printf("年齡: %d\n", std.age); printf("成績: %6.2f\n", std.score); printf("--------------------\n"); printf("是否更改成績?(1為是, 0為否)"); scanf("%d", &doedit); if ( doedit == 1 ) { /* 更改成績 */ printf("請輸入新成績? "); scanf("%f", &score); std.score = score; /* 搜尋指定記錄的檔案指標位置 */ fseek(fp, rec*sizeof(std), SEEK_SET); /* 寫入檔案 */ fwrite(&std, sizeof(std), 1, fp); fflush(fp); /* 輸出緩衝區 */
隨機讀取3 } } else printf("\n記錄編號: %d 找不到!\n", rec); printf("請輸入記錄編號[0-2]? "); scanf("%d", &rec); } fclose(fp); /* 關閉檔案 */ getchar(); }