在前面已經討論了文件打開操作,下面說一下文件的讀寫操作。文件的讀寫操作主要有4種,字符讀寫、字符串讀寫、塊讀寫以及格式化讀寫。
一.字符讀寫
字符讀寫主要使用兩個函數fputc和fgetc,兩個函數的原型是:
int fputc(int ch,FILE *fp);若寫入成功則返回寫入的字符,否則返回-1
int fgetc(FILE *fp); 若讀取成功則返回讀取的字符,否則返回-1
注意:1)對於fputc函數和fgetc函數,每次操作,fputc只能寫入1個字節的數據,無論參數ch多大,只將其低8位的數據寫入到文件中;fgetc 每次只能返回一個字節的數據。
2)對於fgetc函數,若讀取成功則返回讀取到的字符,否則返回-1.這裡面返回-1(即EOF)有兩種情況:一種是讀到文件結束已經沒有任何字符可供讀取了,另一種是讀取出錯。由於通常情況下,在文本文件中可顯字符是不可能出現ASCII碼為-1的字符,因此可以通過fgetc的返回結果判斷文件是否結束(讀取不出錯的情況下)。但是在二進制文件中則不能這麼判斷了,因為二進制文件中很可能就含有FF這樣的數據,如果將存儲fgetc讀取結果的變量ch定義為char型,則不能判斷二進制文件是否結束,但是如果定義為int型,則同樣可以判斷,因為即使讀取的字符是FF,但是由於ch是int型,則事實上ch=0x000000FF,並不等於-1,因此可以判斷文件是否結束。(注意以上所述只在文件讀取不出錯的情況下成立,若文件讀取出錯,是不能這麼判斷文件是否結束,必須通過feof()函數來判斷)
測試程序:
#include<stdio.h> #include<stdlib.h> int main(void) { FILE *fp; int ch; if((fp=fopen("test.txt","wb+"))==NULL) { printf("can not open file\n"); exit(0); } fputc(-1,fp); //-1的二進制為FF fputc(385,fp); //385二進制為110000001 rewind(fp); ch=fgetc(fp); while(feof(fp)==0) { printf("%d\n",ch); ch=fgetc(fp); } fclose(fp); return 0; }
執行結果為:
255
129
Press any key to continue
由於fputc每次只寫入一個字節的數據,因此雖然第二次想寫入385,但是只將其低8位數據寫入,所以輸出結果為129.
若將上述程序中的ch定義為char型,則執行結果為:
-1
-127
Press any key to continue
原因上面已經解釋了.
二.字符串讀寫
字符串讀寫主要涉及到兩個函數fputs和fgets,這兩個函數的原型是:
int fputs(const char *s,FILE *fp);
char *fgets(char *s,int n,FILE *fp);
對於fputs函數,將字符串寫入文件,若寫入成功則返回一個非負值,否則返回-1;
對於fgets函數,從文件中讀取不超過n-1個字符到字符數組中(若文件中字符少於n-1個,則只讀取文件中存在的字符),系統在字符數組末尾自動添加一個'\0',返回字符數組的首地址。
注意:1)對於fgets函數,在讀取過程中,若讀取到字符'\n',則讀取過程提前結束。
測試程序:
#include<stdio.h> #include<stdlib.h> int main(void) { FILE *fp; char s[10]; if((fp=fopen("test.txt","wb+"))==NULL) { printf("can not open file\n"); exit(0); } fputc('A',fp); fputc('B',fp); fputc('\n',fp); fputc('C',fp); rewind(fp); fgets(s,5,fp); printf("%s\n",s); fclose(fp); return 0; }
執行結果為:
AB
Press any key to continue
由此可知當讀取到換行符'\n'時便停止讀取了。
三.塊讀寫
塊讀寫主要涉及到兩個函數fread和fwrite,這兩個函數的原型是:
unsigned int fread(void *buffer,unsigned int size,unsigned int n,FILE *fp);
從文件讀取一組數據存放在首地址為buffer的內存空間中,size為一個數據塊的大小,n為要讀取的數據塊的個數,若讀取成功,則返回讀取的數據的數據塊的個數,否則返回0.
unsigned int fwrite(const void *buffer,unsigned int size,unsigned int n,FILE *fp);
向文件中寫入數據,寫入成功返回寫入數據塊的個數,否則返回0.
塊讀寫一般用於結構體。
注意:1)塊讀寫常用於結構體。
2)fread和fwrite一般成對出現,如果對文件進行寫操作用的是fwrite,則用fread讀取,否則可能會得到意想不到的結果。
測試程序:
#include<stdio.h> #include<stdlib.h> typedef struct node { char name[20]; double score; int age; }Student; int main(void) { FILE *fp; int i; Student s1[3]={{"liudehua",85.5,45},{"zhangxueyou",79.3,47},{"guofucheng",83.4,43}}; Student s2[3]; if((fp=fopen("test.txt","wb+"))==NULL) { printf("can not open file\n"); exit(0); } printf("%d\n",fwrite(s1,sizeof(Student),3,fp)); //printf("%d\n",fwrite(s1,sizeof(s1),1,fp)); //注意和上一句的區別 rewind(fp); printf("%d\n",fread(s2,sizeof(Student),3,fp)); for(i=0;i<3;i++) { printf("%s %lf %d\n",s2[i].name,s2[i].score,s2[i].age); } fclose(fp); return 0; }
執行結果為:
3
3
liudehua 85.500000 45
zhangxueyou 79.300000 47
guofucheng 83.400000 43
Press any key to continue
四.格式化讀寫
格式化讀寫主要涉及到兩個函數:fscanf和fprintf,兩個函數的原型是
int fscanf(FILE *fp,const char *format[,argument]....);
用於從文件格式化讀取數據,若讀取成功,則返回讀取的數據個數,否則返回-1
int fprintf(FILE *fp,const char *format[,argument]....);
用於向文件格式化寫入數據,若寫入成功,則返回寫入的字符個數,否則返回-1
注意:1)格式化讀寫和其他幾種讀寫有很大的不同。格式化讀寫是以我們人所能識別的格式將數據寫入文件,即若以格式化方式寫入一個整型數值65,則其實是寫入的兩個字符'6'和'5',即占2字節,而不是4字節,但是若以塊寫方式寫入,則其占4字節。即在使用格式化讀寫時系統自動進行了一些轉換。
2)fprintf和fscanf函數一般成對出現,若數據是用fprintf進行寫入的,則最好使用fscanf進行讀取。
3)在使用fprintf函數寫入時,若文件是以文本方式打開,如果參數format中包含了'\n',則最後文件中會被寫入換行符;而若文件以二進制方式打開,則文件中不會被寫入換行符,這點區別在上一篇博客中已經提到。
測試程序:
#include<stdio.h> #include<stdlib.h> typedef struct node { char name[20]; double score; int age; }Student; int main(void) { FILE *fp; int i; Student s1[3]={{"liudehua",85.5,45},{"zhangxueyou",79.3,47},{"guofucheng",83.4,43}}; Student s2[3]; if((fp=fopen("test.txt","wb+"))==NULL) { printf("can not open file\n"); exit(0); } for(i=0;i<3;i++) { printf("%d\n",fprintf(fp,"%s %lf %d\n",s1[i].name,s1[i].score,s1[i].age)); } rewind(fp); for(i=0;i<3;i++) { printf("%d\n",fscanf(fp,"%s %lf %d",s2[i].name,&s2[i].score,&s2[i].age)); } for(i=0;i<3;i++) { printf("%s %lf %d\n",s2[i].name,s2[i].score,s2[i].age); } fclose(fp); return 0; }
執行結果:
22
25
24
3
3
3
liudehua 85.500000 45
zhangxueyou 79.300000 47
guofucheng 83.400000 43
Press any key to continue
文件test.txt中的內容是:
若將打開方式改成"wt+",則文件中的內容為:
而若以fread和fwrite方式進行讀寫時,其結果如下:
測試程序:
#include<stdio.h> #include<stdlib.h> typedef struct node { char name[20]; double score; int age; }Student; int main(void) { FILE *fp; Student s1[3]={{"liudehua",85.5,45},{"zhangxueyou",79.3,47},{"guofucheng",83.4,43}}; if((fp=fopen("test.txt","wt+"))==NULL) { printf("can not open file\n"); exit(0); } fwrite(s1,sizeof(s1),1,fp); fclose(fp); return 0; }
則文件中的內容為:
從這裡就可以看出格式化讀寫跟其他方式的區別。
測試程序:
#include<stdio.h> #include<stdlib.h> int main(void) { FILE *fp; int n=32768; if((fp=fopen("test.txt","wt+"))==NULL) { printf("can not open file\n"); exit(0); } fwrite(&n,sizeof(int),1,fp); fclose(fp); return 0; }
執行後,用二進制方式打開文件:
而32768的二進制為00000000100000000000000即00 80 00 00,內容占4個字節。
而
#include<stdio.h> #include<stdlib.h> int main(void) { FILE *fp; int n=32768; if((fp=fopen("test.txt","wt+"))==NULL) { printf("can not open file\n"); exit(0); } fprintf(fp,"%d",n); fclose(fp); return 0; }
執行的結果:
即用fprintf寫入的是51,50,55,54,56,即跟字符'3','2','7','6','8'各自對應的整數值,內容占5個字節
作者 海 子