C語言文件操作之——文件的讀寫(詳解,附學習資料)

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++遊戲編程學習知識和路線方法,群里會不定期更新最新的教程和學習方法,最後祝所有程序員都能夠走上人生巔峰,讓代碼將夢想照進現實


推薦閱讀:

TAG:C編程語言 | 文件 | C語言入門 |