文件輸入輸出函數fgetc/fputc及fgets/fputs等文件指針位置的變化


文件打開后才可以對文件進行操作。也就是說,文件必須經歷打開-操作-關閉的過程。如前所述,C語言對文件的操作都是通過調用標准I/O庫函數來實現的。文件操作實際是指對文件的讀寫。文件的讀操作就是從文件中讀出數據,即將文件中的數據輸入計算機;文件的寫操作是向文件中寫入數據,即向文件輸出數據。實際上對文件的處理過程就是對文件的輸入輸出過程。在前面已經介紹了C語言對標准設備文件的輸入輸出函數,本節討論對磁盤文件的輸入輸出函數,這類文件及其相應的函數在實際應用和文件處理中占據重要的地位。C語言提供的緩沖式文件處理函數可分為:

     字符輸入輸出函數   fgetc和fputc
   字符串輸入輸出函數  fgets和fputs
   格式化輸入輸出函數  fscanf和fprintf
   數據塊輸入輸出函數  fread和fwrite
   文件定位函數     feek、rewind和ftell
   其它函數       feof、ferror和clearerr。

12.3.1 文件的字符輸入/輸出函數

1.字符輸入函數fgetc( )

     fgetc函數的調用形式為:
     ch = fgetc (fp);

     其中fp為文件型指針變量,ch字符變量。

     fgetc函數的功能是:從指定的文件中讀取一個字符。即:從fp所指向的文件(該文件必須是以讀或讀寫方式打開的)中讀取一個字符返回,讀取的字符賦給變量ch。若讀取字符時文件已經結束或出錯,fputc函數返回文件結束標記EOF,此時EOF的值為-1。

     例如,要從磁盤文件中順序讀入字符並在屏幕上顯示,可通過調用fgetc函數實現:
     while ( (c=fgetc(fp)) != EOF )
       putchar(c);

     注意:文件結束標記EOF是不可輸出字符,不能在屏幕上顯示。因為EOF是在頭文件stdio.h中定義的符號常量,其值為-1,而ASCII碼中沒用-1,可見,用它作文件結束標記是合適的。

     例12-1:在屏幕上顯示文本文件的內容。

   #include <stdio.h>
   main ( )
   { FILE *fp;
    char filename[20], ch;
    printf ("Enter filename:");
    scanf("%s",filename); /* 輸入文件名 */
    if ( (fp = fopen (filename,"r"))==NULL) /* 打開文件 */
     { printf("file open error.\n"); /* 出錯處理 */
      exit (0);
     }
    while ( ( ch = fgetc(fp) )!=EOF) /* 從文件中讀字符 */
     putchar(ch); /* 顯示從文件讀入的字符 */
    fclose (fp); /* 關閉文件 */
   }

     例12-2:使用標准輸出文件顯示文本文件的內容。

   #include <stdio.h>
   main ( )
   { FILE *fp;
    char filename[20], ch;
    printf ("Enter filename:");
    scanf("%s",filename); /* 輸入文件名 */
    if ( (fp = fopen (filename,"r"))==NULL) /* 打開文件 */
     { printf("file open error.\n"); /* 出錯處理 */
      exit (0);
     }
    while ( (ch=fgetc(fp) ) != EOF ) /* 從文件中讀取字符 */
     fputc(ch,stdout); /* 向標准輸出文件中輸出(顯示) */
    fclose (fp); /* 關閉文件 */
   }

2.字符輸出函數fputc( )

     fputc函數的調用形式為:
     fputc (ch, fp);

     其中:ch是要輸出的字符(可為字符常數或字符變量),fp為文件型指針變量。

     fputc函數的功能是:將一個字符輸出到指定文件中。即將字符變量ch中的字符輸出到fp所指向的文件。若輸出操作成功,該函數返回輸出的字符;否則,返回EOF。

     例12-3:從鍵盤輸入一字符串,並逐個將字符串的每個字符傳送到磁盤文件file中,當輸入的字符為"#"時停止輸入。

   #include <stdio.h> /* 凡程序中用到標准輸入輸出函數,必須包含此文件頭 */
   main ( )
   { FILE *fp; /* 指向磁盤文件file的指針 */
    char ch; /* 暫存讀入字符的字符變量 */
    char filename[15]; /* 存放磁盤文件名的字符數組 */
    scanf("%s", filename); /* 從鍵盤輸入磁盤文件名 */
    if ((fp=fopen(filename,"w"))==NULL) /* 以寫方式打開文本文件並判定是否能正常打開 */
     { printf("Cannot open file.\n"); /* 不能正常打開磁盤文件的處理 */
      exit(0); /* 調用函數exit終止程序運行 */
     }
    while ( (ch=getchar( )) != '#' ) /* 判斷輸入的是否為字符符串結束標志 */
     fputc(ch, fp); /* 讀入的字符寫入磁盤文件 */
    fclose(fp); /* 操作結束關閉磁盤文件 */
   }

     例12-4:請編程完成文本文件的復制。

   #include <stdio.h>
   main ( )
   { FILE *fp1, *fp2;
    char file1[20], file2[20], ch;
    printf ("Enter filename1:");
    scanf("%s",file1);
    printf ("Enter filename2:");
    scanf("%s",file2);
    if ( (fp1=fopen(file1,"r")) == NULL ) /* 以"只讀"方式打開文件1 */
     { printf("file1 open error.\n");
      exit (0);
     }
    if ( (fp2=fopen(file2, "w"))== NULL ) /* 以"寫"方式打開文件2 */
     { printf("file2 open error.\n");
      exit (0);
     }
    while ( ( ch = fgetc(fp1) ) != EOF ) /* 從文件fp1中讀字符 */
     fputc (ch, fp2); /* 寫入文件fp2中 */
    fclose (fp1); /* 關閉兩個文件 */
    fclose (fp2);
   }

12.3.2 文件的字符串輸入/輸出函數

     對文件的輸入輸出,除了前面介紹的以字符為單位進行處理之外,還允許以字符串為單位進行處理,這也被稱為"行處理"。

     C語言提供fgets和fputs函數實現文件的按字符串的讀寫。

1.字符串輸入函數fgets( )

     fgets函數的調用形式:
     fgets (s, n, fp);

     其中:參數s可以是一個字符數組名,或是指向字符串的指針,n為要讀取的最多的字符個數;fp是指向該文件的文件型指針。

     fgets函數的功能是:從fp所指向的文件中讀取長度不超過n-1個字符的字符串,並將該字符串放到字符數組s中。如果操作正確,函數的返回值為字符數組s的首地址;如果文件結束或出錯,則函數的返回值為NULL。

     情況1:從文件中已經讀入了n-1個連續的字符,還沒有遇到文件結束標志或行結束標志'\n',
     則:s中存入n-1個字符,串尾以串結束標記'\0'結束。

     情況2:從文件中讀入字符遇到了行結束標志'\n',
     則:s中存入實際讀入的字符,串尾為'\n'和'\0'。

     情況3:在讀文件的過程中遇到文件尾(文件結束標志EOF),
     則:s中存入實際讀入的字符,串尾為'\0'。文件結束標志EOF不會存入數組。

     情況4:當文件已經結束仍然繼續讀文件,或讀取文件內容發生錯誤,
     則:函數的返回值為NULL,表示文件結束。例如:現有一個有兩行字符的ASCII文件,文件打開后,文件的讀寫位置指針如圖12-3所示。

     若有:char s[5];FILE *fp;fp為指向該文件的指針。則多次執行語句"fgets (s, 5, fp);",每次的執行結果如下:

第1次執行語句fgets (s, 5, fp):
   文件剛打開時,文件的讀寫位置指針指向了文件的第1個字符,執行語句:fgets (s, 5, fp)之后,從fp指向的文件中讀取的字符串是"abcd\n",文件的讀寫位置指針向前移動了4個字符,字符串在s中的存儲形式和文件讀寫位置指針如圖12.4所示。

第2次執行語句fgets (s, 5, fp):
   從文件的讀寫位置指針開始,順序讀入字符,遇到'\n'字符后,函數執行完畢。字符串在s中的存儲形式和文件讀寫位置指針如圖12.5所示。

第3次執行語句fgets (s, 5, fp):
   從文件的讀寫位置指針開始,順序讀入字符,遇到文件結束標記EOF,函數執行完畢,此時,文件的讀寫位置指針指向了文件最后一個字符的后面。字符串在s中的存儲形式和文件讀寫位置指針如圖12-6所示。

     第4次執行語句fgets (s, 5, fp):
   由於文件的讀寫位置指針已經指向了文件結束標記EOF,所以函數的返回值為NULL,表示文件已經結束,文件的讀寫位置指針沒有變化。文件讀寫位置指針如圖12-7所示。

     例12-5:顯示文件內容並加上行號。

   #include <stdio.h>
   main ( )
   { FILE * fp;
    char file[20], str[10];
    int flag=1, i=0; /* flag標志變量,為1:開始新行。i為行號 */
    printf ("Enter filename:");
    scanf("%s",file);
    if ( ( fp = fopen (file, "r")) == NULL ) /* 打開文件 */
     { printf("file open error.\n");
      exit (0); 
     }
    while ( fgets( str,10,fp )!=NULL ) /* 從文件中讀出字符串 */
     { if (flag) printf ("%3d:%s", ++i, str); /* 顯示行號 */
       else printf ("%s", str);
      if ( str [strlen(str)-1] == '\n' ) flag=1;
       else flag=0;
     }
    fclose (fp);
   }

     本程序的特點是使用一個長度僅為10的小數組來處理文件,程序中充分利用了函數fgets的特點。

2.字符串輸出函數 fputs( )

     fputs函數的調用形式:
     fputs (s, fp);

     其中:s為指向字符串的指針或字符數組名,也可以是字符串常量;fp是指向將要被寫入的文件的文件型指針。

     fputs函數的功能是:將s指向的字符串或字符串常量寫入fp指向的文件。輸出的字符串寫入文件時,字符'\0'被自動舍去。函數調用成功,則返回值為0;否則返回EOF。

     例12-6:從鍵盤輸入若干行字符存入磁盤文件file.txt中

   #include <stdio.h>
   #include <string.h>
   main ( )
   { FILE *fp;
    char str[81];
    if ((fp=fopen("file.txt", "w")) == NULL)
       /* 以寫方式打開磁盤文本文件file.txt並判斷打開操作正常與否 */
     { printf("Cannot open file.\n"); /* 不能正常打開磁盤文件的處理 */
      exit(0);
     }
    while ( strlen(gets(str)) > 0 )
       /* 讀入從鍵盤輸入的一行字符,送入str字符數組 */
    { fputs(str, fp); /* 若該字符串非空則送入磁盤文件file.txt中去 */
     fputs("\n", fp);
    }
    fclose (fp); /* 操作結束關閉磁盤文件 */
   }

     例12-7:復制文本文件。

   #include <stdio.h>
   main ( )
   { FILE *fp1, *fp2;
    char file1[20], file2[20], s[10];
    printf ("Enter filename1:");
    scanf("%s",file1);
    printf ("Enter filename2:");
    scanf("%s",file2);
    if ( ( fp1 = fopen (file1, "r")) == NULL ) /* 打開文本文件1 */
     { printf("file1 open error.\n"); 
      exit (0);
     }
    if ( ( fp2 = fopen (file2, "w")) == NULL ) /* 打開文本文件2 */
     { printf("file2 open error.\n"); 
      exit (0);
     }
    while ( fgets( s,10,fp1 ) != NULL ) /* 從文件fp1中讀出字符串 */
     fputs ( s, fp2 ); /* 將字符串寫入文件fp2中 */
    fclose (fp1);
    fclose (fp2);
   }

12.3.3 文件的格式化輸入輸出函數

     前面的章節中介紹了scanf和printf兩個格式化輸入輸出函數,它們適用於標准設備文件。C標准函數庫還提供了fscanf和fprintf兩個格式化輸入輸出函數,以滿足磁盤文件格式化輸入輸出的需要。

1.格式化輸入函數 fscanf( )

     fscanf函數的調用形式:
     fscanf (fp, 格式控制串, 輸入列表);

     其中:fp指向將要讀取文件的文件型指針,格式控制串和輸入列表的內容、含義及對應關系與第二章中介紹的scanf函數相同。

     fscanf函數的功能是:從fp指向的文件中,按格式控制符讀取相應數據賦給輸入列表中的對應變量地址中。例如,
     fscanf (fp, "%d,%f", &i, &t);
   完成從指定的磁盤文件上讀取ASCII字符,並按"%d"和"%f"型格式轉換成二進制形式的數據送給變量i和t。

2.格式化輸出函數 fprintf( )

     fprintf函數的調用形式:
     fprintf (fp, 格式控制串, 輸出列表);

     其中:fp指向將要寫入文件的文件指針,格式控制串和輸出列表的內容及對應關系與前面章節中介紹的printf函數相同。

     fprintf函數的功能是:將輸出列表中的各個變量或常量,依次按格式控制符說明的格式寫入fp指向的文件。該函數調用的返回值是實際輸出的字符數。

     例12-8.C:從鍵盤輸入一個字符串和一個十進制整數,將它們寫入test文件中,然后再從test文件中讀出並顯示在屏幕上。

   #include <stdio.h>
   main( )
   { char s[80];
    int a;
    FILE *fp;
    if ((fp=fopen("test", "w")) == NULL)  /* 以寫方式打開文本文件 */
     { printf ("Cannot open file.\n");
      exit(1);
     }
    fscanf (stdin, "%s%d", s, &a); /* 從標准輸入設備(鍵盤)上讀取數據 */
    fprintf(fp, "%s %d", s, a); /* 以格式輸出方式寫入文件 */
    fclose (fp); /* 寫文件結束關閉文件 */
    if ((fp=fopen("test", "r")) == NULL)   /* 以讀方式打開文本文件 */
     { printf ("Cannot open file.\n");
      exit(1);
     }
    fscanf (fp, "%s%d", s, &a); /* 以格式輸入方式從文件讀取數據 */
    fprintf(stdout, "%s %d\n", s, a); /* 將數據顯示到標准輸出設備(屏幕)上 */
    fclose(fp); /* 讀文件結束關閉文件 */
   }

12.3.4 文件的數據塊輸入/輸出函數

     這類函數是ANSI C標准對緩沖文件系統所做的擴充,以方便文件操作實現一次讀寫一組數據的功能。例如采用這種方式對數組和結構進行整體的輸入輸出是比較方便的。

1.文件數據塊讀函數fread( )

     fread函數的調用形式:
     fread ( buffer, size, count, fp);

     其中:buffer是一個指針,是指向輸入數據存放在內存區的起始地址;size是要輸入的字節數;count是要輸入大小為size個字節的數據塊的個數;fp是文件指針。

     fread函數的功能是:對fp所指向的文件讀取count次,每次讀取一個大小為size的數據塊,將讀取的各數據塊存到buffer指向的內存區。該函數的返回值是實際讀取的count的值。

2.文件數據塊寫函數fwrite( )

     fwrite函數的調用形式:
     fwrite ( buffer, size, count, fp);

     fwrite函數的參數及其功能與fread函數類似,只是對文件的操作而言是互逆的,一個是讀取,一個是寫入。

例12-9:從鍵盤輸入3個學生的數據,將它們存入文件student;然后再從文件中讀出數據,顯示在屏幕上。

   #include <stdio.h>
   #define SIZE 3
   struct student /* 定義結構 */
   { long num;
    char name[10];
    int age;
    char address[10];
   } stu[SIZE], out;

   void fsave ( )
   { FILE *fp;
    int i;
    if (( fp=fopen("student","wb")) == NULL )  /* 以二進制寫方式打開文件 */
     { printf ("Cannot open file.\n"); /* 打開文件的出錯處理 */
      exit(1); /* 出錯后返回,停止運行 */
     }
    for (i=0; i<SIZE; i++) /* 將學生的信息(結構)以數據塊形式寫入文件 */
     if (fwrite(&stu[i], sizeof(struct student), 1, fp) != 1)
       printf("File write error.\n"); /* 寫過程中的出錯處理 */
    fclose (fp); /* 關閉文件 */
   }

   main ( )
   { FILE *fp;
    int i;
    for (i=0; i<SIZE; i++)   /* 從鍵盤讀入學生的信息(結構) */
    { printf("Input student %d:", i+1);
     scanf ("%ld%s%d%s", &stu[i].num, stu[i].name, &stu[i].age, stu[i].address );
    }
    fsave( ); /* 調用函數保存學生信息 */
    fp = fopen ("student", "rb"); /* 以二進制讀方式打開數據文件 */
    printf (" No. Name Age Address\n");
    while ( fread(&out, sizeof(out), 1, fp) ) /* 以讀數據塊方式讀入信息 */
     printf ("%8ld %-10s %4d %-10s\n", out.num, out.name, out.age, out.address );
    fclose(fp); /* 關閉文件 */
   }


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM