文件输入输出函数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); /* 关闭文件 */
   }

posted @ 2016-04-10 15:18  甘乐  阅读(3934)  评论(0编辑  收藏  举报