C語言文件操作之——文件的讀寫(詳解,附學習資料)
來自專欄雲志c語言編程1 人贊了文章
不關注小編,你會錯過很多知識哦。溫馨提示:亮點在最後!
當文件按指定的工作方式打開以後,就可以執行對文件的讀和寫。下面按文件的性質分類進行操作。針對文本文件和二進位文件的不同性質,對文本文件來說,可按字元讀寫或按字元串讀寫;對二進位文件來說,可進行成塊的讀寫或格式化的讀寫。
1. 讀寫字元
C提供fgetc和fputc函數對文本文件進行字元的讀寫,其函數的原型存於stdio.h頭文件中,格式為:
int fgetc(FILE *stream)
fgetc( )函數從輸入流的當前位置返回一個字元,並將文件指針指示器移到下一個字元處,如果已到文件尾,函數返回EOF,此時表示本次操作結束,若讀寫文件完成,則應關閉文件。
int fputc(int ch,FILE *stream)
fputc()函數完成將字元c h的值寫入所指定的流文件的當前位置處,並將文件指針後移一位。fputc()函數的返回值是所寫入字元的值,出錯時返回EOF。
[例1] 將存放於磁碟的指定文本文件按讀寫字元方式逐個地從文件讀出,然後再將其顯示到屏幕上。採用帶參數的main( ),指定的磁碟文件名由命令行方式通過鍵盤給定。
#i nclude<stdio.h>
main(argc,argv)
int argc;
char *argv[];
{
char ch;
FILE *fp;
int i;
if((fp=fopen(argv[1],"r"))==NULL) /* 打開一個由argv[1]所指的文件*/
{
printf("not open");
exit(0);
}
while ((ch=fgetc(fp))!=EOF) /* 從文件讀一字元,顯示到屏幕*/
putchar(ch);
fclose(fp);
}
程序是一帶參數的main( )函數,要求以命令行方式運行,其參數argc是用於記錄輸入參數的個數, argv是指針數組,用於存放輸入參數的字元串,串的個數由argc描述。假設我們指定讀取的文件名為L8-2.c,並且列表文件內容就是源程序。經過編 譯和連接生成可執行的文件L8-2.exe。運行程序l8-2.exe,輸入的命令行方式為:
c:/tc>l8-2 L8-2.c
上述程序以命令行方式運行,其輸入參數字元串有兩個,即argv[0]="c:/tc>l8-2"、argv[1]=" L8-2.c ",argc = 2。故打開的文件是L8-2.c 。程序中對fgetc( )函數的返回值不斷進行測試,若讀到文件尾部或讀文件出錯,都將返回C的整型常量EOF,其值為非零有效整數。程序的運行輸出為源程序本身:
c:/tc>l8-2 L8-2.c
#i nclude <stdio.h>
main( argc,argv)
int argc;
char *argv[];
{
char ch;
FILE *fp;
int i;
if((fp=fopen(argv[1],"r"))==NULL) /* 打開一個由argv[1] 所指的文件*/
{
printf("not open");
exit(0);
}
while ((ch=fgetc(fp))!=EOF) /* 從文件讀一字元,顯示到屏幕*/
putchar(ch);
fclose(fp);
}
[例2] 從鍵盤輸入字元,存到磁碟文件test.txt中:
#i nclude <stdio.h>
main( )
{
FILE fp; / *定義文件變數指針* /
char ch;
if((fp=fopen("test.txt","w"))==NULL) /*以只寫方式打開文件*/
{
printf("cannot open file!/n");
exit(0);
}
while ((ch=fgetchar())!=/n) /*只要輸入字元非回車符* /
fputc(ch,fp) /*寫入文件一個字元*/
fclose(fp);
}
程序通過從鍵盤輸入一以回車結束的字元串,寫入指定的流文件test.txt,文件以文本只寫方式打開,所以流文件具有可讀性,能支持各種字元處理工具訪問。簡單地說,我們可以通過DOS提供的type命令來列表顯示文件內容。
運行程序:
I love china!
在DOS操作系統環境下,利用type 命令顯示test.txt文件如下:
c:/tc> type test.txt
I love china!
2. 讀寫字元串
C提供讀寫字元串的函數原型在stdio.h頭文件中,其函數形式為:
Char *fgets(char *str,int num,FILE *stream)
fgets() 函數從流文件stream中讀取至多num-1個字元,並把它們放入str指向的字元數組中。讀取字元直到遇見回車符或E O F(文件結束符)為止,或讀入了所限定的字元數。
int fputs(char *str,FILE *stream)
fputs( )函數將str指向的字元串寫入流文件。操作成功時,函數返回0值,失敗返回非零值。
[例3] 向磁碟寫入字元串,並寫入文本文件test.txt:
#i nclude<stdio.h>
#i nclude<string.h>
main( )
{
FILE *fp;
char str[128];
if ((fp=fopen("test.txt","w"))==NULL) /*打開只寫的文本文件*/
{
printf("cannot open file!");
exit(0);
}
while((strlen(gets(str)))!=0)
{ /*若串長度為零,則結束*/
fputs(str,fp); /*寫入串*/
fputs("/n",fp); /*寫入回車符*/
}
fclose(fp); /*關文件*/
}
運行該程序,從鍵盤輸入長度不超過1 2 7個字元的字元串,寫入文件。如串長為0,即空串,程序結束。
輸入:Hello!
How do you do
Good-bye!
運行結束後,我們利用dos的type命令列表文件:
c:/tc>type test.txt
Hello!
How do you do
Good-bye!
這裡所輸入的空串,實際為一單獨的回車符,其原因是gets函數判斷串的結束是以回車作標誌的。
[例4] 從一個文本文件test1.txt中讀出字元串,再寫入令一個文件test2.txt。
#i nclude<stdio.h>
#i nclude<string.h>
main( )
{
FILE *fp1,*fp2;
char str[128];
if ((fp1=fopen("test1.txt","r"))==NULL)
{ / * 以只讀方式打開文件1 */
printf("cannot open file/n");
exit(0);
}
if((fp2=fopen("test2.txt","w"))==NULL)
{ /*以只寫方式打開文件2 */
printf("cannot open file/n");
exit(0);
}
while ((strlen(fgets(str,128,fp1)))>0)
/*從文件中讀回的字元串長度大於0 */
{
fputs(str,fp2 ); /* 從文件1讀字元串並寫入文件2 */
printf("%s",str); /*在屏幕顯示*/
}
fclose(fp1);
fclose(fp2);
}
程序共操作兩個文件,需定義兩個文件變數指針,因此在操作文件以前,應將兩個文件以需要的工作方式同時打開(不分先後),讀寫完成後,再關閉文件。設計過 程是按寫入文件的同時顯示在屏幕上,故程序運行結束後,應看到增加了與原文件相同的文本文件並顯示文件內容在屏幕上。
3. 格式化的讀寫
前面的程序設計中,我們介紹過利用scanf( )和printf( )函數從鍵盤格式化輸入及在顯示器上進行格式化輸出。對文件的格式化讀寫就是在上述函數的前面加一個字母f成為fscanf( )和fprintf( )。其函數調用方式:
int fscanf(FILE *stream,char *format,arg_list)
int fprintf(FILE *stream,char *format,arg_list)
其中,stream為流文件指針,其餘兩個參數與scanf( )和printf( )用法完全相同。
[例5] 將一些格式化的數據寫入文本文件,再從該文件中以格式化方法讀出顯示到屏
幕上,其格式化數據是兩個學生記錄,包括姓名、學號、兩科成績。
#i nclude<stdio.h>
main( )
{
FILE *fp;
int i;
struct stu{ /*定義結構體類型*/
char name[15];
char num[6];
float score[2];
}student; /*說明結構體變數*/
if((fp=fopen("test1.txt","w"))==NULL)
{ /*以文本只寫方式打開文件*/
printf("cannot open file");
exit(0);
}
printf("input data:/n");
for( i=0;i<2;i++)
{
scanf("%s %s %f %f",student.name,student.num,&student.score[0],
&student.score[1]); /*從鍵盤輸入*/
fprintf(fp,"%s %s %7.2f %7.2f/n",student.name,student.num,
student.score[0],student.score[1]); /* 寫入文件*/
}
fclose(fp); /*關閉文件*/
if((fp=fopen("test.txt","r"))==NULL)
{ /*以文本只讀方式重新打開文件*/
printf("cannot open file");
exit(0);
}
printf("output from file:/n");
while (fscanf(fp,"%s %s %f %f/n",student.name,student.num,&student.score[0],student.score[1])!=EOF)
/ *從文件讀入* /
printf("%s %s %7.2f %7.2f/n",student.name,student.num,
student.score[0],student.score[1]); /* 顯示到屏幕*/
fclose(fp); /*關閉文件*/
}
程序設計一個文件變數指針,兩次以不同方式打開同一文件,寫入和讀出格式化數據,有一點很重要,那就是用什麼格式寫入文件,就一定用什麼格式從文件讀,否則,讀出的數據與格式控制符不一致,就造成數據出錯。上述程序運行如下:
input data:
xiaowan j001 87.5 98.4
xiaoli j002 99.5 89.6
output from file:
xiaowan j001 87.50 98.40
xiaoli j002 99.50 89.60
列表文件的內容顯示為:
c:/>type test.txt
xiaowan j001 87.50 98.40
xiaoli j002 99.50 89.60
此程序所訪問的文件也可以定為二進位文件,若打開文件的方式為:
if ((fp=fopen("test1.txt","wb"))==NULL)
{ / * 以二進位只寫方式打開文件* /
printf("cannot open file");
exit(0);
}
其效果完全相同。
4. 成塊讀寫
前面介紹的幾種讀寫文件的方法,對其複雜的數據類型無法以整體形式向文件寫入或從文件讀出。C語言提供成塊的讀寫方式來操作文件,使其數組或結構體等類型可以進行一次性讀寫。成塊讀寫文件函數的調用形式為:
int fread(void *buf,int size,int count,FILE *stream)
int fwrite(void *buf,int size,int count,FILE *stream)
fread()函數從stream 指向的流文件讀取count (欄位數)個欄位,每個欄位為size(欄位長度)個字元長,並把它們放到b u f(緩衝區)指向的字元數組中。
fread()函數返回實際已讀取的欄位數。若函數調用時要求讀取的欄位數超過文件存放的欄位數,則出錯或已到文件尾,實際在操作時應注意檢測。
fwrite( )函數從buf(緩衝區)指向的字元數組中,把count(欄位數)個欄位寫到stream所指向的流中,每個欄位為size個字元長,函數操作成功時返回所寫欄位數。
關於成塊的文件讀寫,在創建文件時只能以二進位文件格式創建。
[例6] 向磁碟寫入格式化數據,再從該文件讀出顯示到屏幕。
#i nclude "stdio.h"
#i nclude "stdlib.h"
main( )
{
FILE *fp1;
int i;
struct stu{ / *定義結構體*/
char name[15];
char num[6];
float score[2];
}student;
if((fp1=fopen("test.txt","wb"))==NULL)
{ /*以二進位只寫方式打開文件* /
printf("cannot open file");
exit(0);
}
printf("input data:/n");
for( i=0;i<2;i++)
{
scanf("%s %s %f %f",student.name,student.num,&student.score[0],&student.score[1]); /* 輸入一記錄*/
fwrite(&student,sizeof(student),1,fp1); /* 成塊寫入文件*/
}
fclose(fp1);
if((fp1=fopen("test.txt","rb"))==NULL)
{ /*重新以二進位只寫打開文件*/
printf("cannot open file");
exit(0);
}
printf("output from file:/n");
for (i=0;i<2;i++)
{
fread(&student,sizeof(student),1,fp1); /* 從文件成塊讀*/
printf("%s %s %7.2f %7.2f/n",student.name,student.num,student.score[0],student.score[1]); /* 顯示到屏幕*/
}
fclose(fp1);
}
運行程序:
input data:
xiaowan j001 87.5 98.4
xiaoli j002 99.5 89.6
output from file:
xiaowan j001 87.50 98.40
xiaoli j002 99.50 89.60
通常,對於輸入數據的格式較為複雜的話,我們可採取將各種格式的數據當做字元串輸入,然後將字元串轉換為所需的格式。C提供函數:
int atoi(char *ptr)
float atof(char *ptr)
long int atol(char *ptr)
它們分別將字元串轉換為整型、實型和長整型。使用時請將其包含的頭文件math.h或stdlib.h寫在程序的前面。
寫在最後
關於怎麼快速學C/C++,可以加下小編的C/C++學習群:,814+974+917,邀請碼:雲志,不管你是小白還是大牛,小編我都歡迎,不定期分享乾貨,歡迎初學和進階中的小夥伴。
每天晚上20:00都會開直播給大家分享C/C++遊戲編程學習知識和路線方法,群里會不定期更新最新的教程和學習方法,最後祝所有程序員都能夠走上人生巔峰,讓代碼將夢想照進現實
推薦閱讀: