读写流-fgetc、fputc、fgets、fputs、fread、ferror、fwrite、clearerr、ungetc

来源:互联网 发布:万德数据库怎么购买 编辑:程序博客网 时间:2024/05/22 01:25

一旦打开了流,则可以对流进行读写:每次一个字符,每次一行,二进制。

1.每次一个字符

使用下面三个函数用于一次读一个字符。
[cpp] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. #include <stdio.h>  
  2. int getc(FILE* fp);  
  3. int fgetc(FILE* fp);  
  4. int getchar(void);  
如果成功返回读取到的字符,出错或者到达文件结尾则返回EOF(一般为-1)。
getc为宏,fgetc为函数,getchar等价于fgetc(stdin)。
注意:不管是出错还是达到文件结尾,三个函数都返回相同的值,为了区分这2中情况,必须调用ferror或者feof函数。
[cpp] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. #include <stdio.h>  
  2. int ferror(FILE* fp);  
  3. int feof(FILE* fp);  
如果条件为真则返回非0值(真),否则返回0(假)。
在大多数实现中,为每个流在FILE结构体中维持了2个标志:
  • 出错标志
  • 文件结束标志
调用clearerr函数则清除这两个标志。
[cpp] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. #include <stdio.h>  
  2. void clearerr(FILE* fp);  
实践:
[cpp] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. #include <stdio.h>  
  2.   
  3. int main(void){  
  4.         int c;  
  5.         while((c = fgetc(stdin)) != EOF){  
  6.                 fputc(c,stdout);  
  7.         }  
  8.         if(ferror(stdin) > 0){  
  9.                 printf("stdin error.\n");  
  10.         }else if(feof(stdin) > 0){  
  11.                 printf("stdin eof.\n");  
  12.         }  
  13.   
  14.         clearerr(stdin);  
  15.   
  16.         if(ferror(stdin) > 0){  
  17.                 printf("stdin error after clear.\n");  
  18.         }else if(feof(stdin) > 0){  
  19.                 printf("stdin eof after clear.\n");  
  20.         }  
  21.         return 0;  
  22. }  
运行结果:
yan@yan-vm:~/apue$ ./a.out
12345
12345
stdin eof.

从流中读取数据以后,可以调用ungetc将字符再压送回流中。
[cpp] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. #include <stdio.h>  
  2. int ungetc(int c, FILE* fp);  
压送回流中的字符以后又可以从流中读出,但是读出字符的顺序与压送回的顺序相反。回送的字符不必一定是上一次读取的字符,
不能回送EOF,但是已经到达文件尾端时,仍可以回送一字符。下次读将返回该字符,再次读则返回EOF。
该函数使用的场合是:当正在读一个输入流,并进行某种形式的分字或分记号操作,会经常用到回送字符操作。有时需要先看一下
下一个字符,以决定如何处理当前字符。然后就需要方便地将当看完的字符送回,以便下一次调用getc时返回该字符。如果标准
IO库不提供回送能力,就需要将该字符存放在一个我们自己的变量中,并设置一个标准以便判断在下一次需要一个字符时是调用
getc还是从我们自己的变量中取用。
实践:
[cpp] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. #include <stdio.h>  
  2.   
  3. int main(void){  
  4.         int c;  
  5.         if((c = fgetc(stdin)) != EOF){  
  6.                 fputc(c,stdout);  
  7.         }  
  8.         ungetc(c,stdin);  
  9.         ungetc(c+1,stdin);  
  10.         while((c = fgetc(stdin)) != EOF){  
  11.                 fputc(c,stdout);  
  12.         }  
  13.         printf("\n");  
  14.         return 0;  
  15. }  
运行结果:
yan@yan-vm:~/apue$ ./a.out
a
aba

对应于上面所述的每个输入函数都有一个输出函数对应。
[cpp] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. #include <stdio.h>  
  2. int putc(int c, FILE* fp);  
  3. int fputc(int c, FILE* fp);  
  4. int putchar(int c);  
与输入函数一样,putc为宏,fputc为函数,putchar等价于fputc(stdout)。

2.每次一行IO

下面两个函数提供每次输入一行的功能。
[cpp] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. #include <stdio.h>  
  2. char* fgets(char* restrict buf, int n, FILE* restrict fp);  
  3. char* gets(char * buf);  
如果成功返回buf,如果出错或者文件已经到达结尾则返回NULL。
对于fgets必须指定缓冲区的长度n,此函数一直读到下一个换行符为止(换行符也被送入到缓冲区),但是不超过n-1个字符,
读入的字符被送入缓冲区,该缓冲区以NULL字符结尾。如果该行的字符数(包括最后一个换行符)超过n-1,则fgets只返回一个
不完整的行,但是缓冲区总是以NULL字符结尾,对fgets的下一次调用会继续读该行。
gets是一个不推荐的函数。因为没有指定缓冲区的长度,这样就很可能造成缓冲区溢出。gets与fgets的另一个区别是,gets并
不将换行符存入缓冲区。

fputs和puts提供每次输出一行的功能。
[cpp] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. #include <stdio.h>  
  2. int fputs(const char* restrict str, FILE* restrict fp);  
  3. int puts(const char* str);  
如果成功则返回非负值,出错则返回EOF。
函数fputs将一个以NULL符终止的字符串写到指定的流,尾端的终止符NULL不写出。注意,这并不一定是每次输出一行,因为
它并不要求在NULL符之前一定是换行符。
puts将一个以NULL符终止的字符串写到标准输出,终止符不写出。但是,puts然后又将一个换行符写到标准输出。
puts并不像gets那样不安全,但是我们还是应该避免使用它,因为puts会自己加上一个换行符,而如果我们使用fgets和fputs,
我们需要自己处理换行符。
实践:
[cpp] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. #include <stdio.h>  
  2.   
  3. int main(void){  
  4.         int result = 0;  
  5.         char buf[256];  
  6.         FILE* fp;  
  7.         if((fp = fopen("a.txt""r+")) == NULL){  
  8.                 result = -1;  
  9.                 perror("fopen");  
  10.                 goto FINALLY;  
  11.         }  
  12.   
  13.         while(fgets(buf,256,fp) != NULL){  
  14.                 fputs(buf,stdout);  
  15.         }  
  16.   
  17. FINALLY:  
  18.         if(fp != NULL){  
  19.                 fclose(fp);  
  20.         }  
  21.         return result;  
  22. }  
运行结果:
yan@yan-vm:~/apue$ cat a.txt
123
456
yan@yan-vm:~/apue$ ./a.out
123
456
yan@yan-vm:~/apue$

如果将上面的
[cpp] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. fputs(buf,stdout);  
修改成
[cpp] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. puts(buf);  
则结果为:
yan@yan-vm:~/apue$ ./a.out
123

456

yan@yan-vm:~/apue$
puts自动又将一个换行符写到标准输出。

3.二进制IO

下面2个函数执行二进制IO操作。
[cpp] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. #include <stdio.h>  
  2. size_t fread(void* restrict ptr, size_t size, size_t nobj, FILE* restrict fp);  
  3. size_t fwrite(const void* restrict ptr, size_t size, size_t nobj, FILE* restrict fp);  
函数返回读或者写的对象数,其中size为每个元素的长度,nobj为欲写入元素的数量。
和getc函数一样,不管是出错还是达到文件结尾,函数都返回相同的值EOF,为了区分这2中情况,必须调用ferror或者feof函数。
函数常见的用法如下:
1.读写一个二进制数组。
[cpp] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. #include <stdio.h>  
  2.   
  3. int main(void){  
  4.         int result = 0;  
  5.         int data[10] = {0,1,2,3,4,5,6,7,8,9};  
  6.         int data2[10] = {0};  
  7.         FILE* fp;  
  8.   
  9.         if((fp = fopen("bfile","wb+")) == NULL){  
  10.                 result = -1;  
  11.                 perror("fopen");  
  12.                 goto FINALLY;  
  13.         }  
  14.   
  15.         if(fwrite(&data[1], sizeof(int), 3, fp) < 0){  
  16.                 result = -1;  
  17.                 perror("fwrite");  
  18.                 goto FINALLY;  
  19.         }  
  20.   
  21.         fclose(fp);  
  22.   
  23.         if((fp = fopen("bfile","rb+")) == NULL){  
  24.                 result = -1;  
  25.                 perror("fopen");  
  26.                 goto FINALLY;  
  27.         }  
  28.   
  29.         if(fread(data2, sizeof(int), 3, fp) < 0){  
  30.                 result = -1;  
  31.                 perror("fread");  
  32.                 goto FINALLY;  
  33.         }  
  34.   
  35.         int i;  
  36.         for(i=0;i<10;i++){  
  37.                 printf("i=%d:%d\n",i,data2[i]);  
  38.         }  
  39.   
  40. FINALLY:  
  41.         if(fp != NULL){  
  42.                 fclose(fp);  
  43.         }  
  44.         return result;  
  45. }  
运行结果:
yan@yan-vm:~/apue$ ./a.out
i=0:1
i=1:2
i=2:3
i=3:0
i=4:0
i=5:0
i=6:0
i=7:0
i=8:0
i=9:0
注意:不是将1写3遍,而是顺序写1,2,3.

2.读写一个结构。
[cpp] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. #include <stdio.h>  
  2.   
  3. typedef struct{  
  4.         int a;  
  5.         char b;  
  6. }myst;  
  7.   
  8. int main(void){  
  9.         int result = 0;  
  10.         FILE* fp;  
  11.         myst st1,st2;  
  12.         st1.a = 1;  
  13.         st1.b = 'a';  
  14.   
  15.         if((fp = fopen("bfile","wb+")) == NULL){  
  16.                 result = -1;  
  17.                 perror("fopen");  
  18.                 goto FINALLY;  
  19.         }  
  20.   
  21.         if(fwrite(&st1, sizeof(myst), 1, fp) < 0){  
  22.                 result = -1;  
  23.                 perror("fwrite");  
  24.                 goto FINALLY;  
  25.         }  
  26.   
  27.         fclose(fp);  
  28.   
  29.         if((fp = fopen("bfile","rb+")) == NULL){  
  30.                 result = -1;  
  31.                 perror("fopen");  
  32.                 goto FINALLY;  
  33.         }  
  34.   
  35.         if(fread(&st2, sizeof(myst), 1, fp) < 0){  
  36.                 result = -1;  
  37.                 perror("fread");  
  38.                 goto FINALLY;  
  39.         }  
  40.   
  41.         printf("st2.a=%d\n",st2.a);  
  42.         printf("st2.b=%c\n",st2.b);  
  43.   
  44. FINALLY:  
  45.         if(fp != NULL){  
  46.                 fclose(fp);  
  47.         }  
  48.         return result;  
  49. }  
运行结果:
yan@yan-vm:~/apue$ ./a.out
st2.a=1
st2.b=a
阅读全文
0 0
原创粉丝点击