读和写流

转自  http://blog.csdn.net/todd911/article/details/12884735

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

1.每次一个字符

使用下面三个函数用于一次读一个字符。

[cpp] view plaincopy

  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 plaincopy

  1. #include <stdio.h>
  2. int ferror(FILE* fp);
  3. int feof(FILE* fp);

如果条件为真则返回非0值(真),否则返回0(假)。

在大多数实现中,为每个流在FILE结构体中维持了2个标志:

  • 出错标志
  • 文件结束标志

调用clearerr函数则清除这两个标志。

[cpp] view plaincopy

  1. #include <stdio.h>
  2. void clearerr(FILE* fp);

实践:

[cpp] view plaincopy

  1. #include <stdio.h>
  2. int main(void){
  3. int c;
  4. while((c = fgetc(stdin)) != EOF){
  5. fputc(c,stdout);
  6. }
  7. if(ferror(stdin) > 0){
  8. printf("stdin error.\n");
  9. }else if(feof(stdin) > 0){
  10. printf("stdin eof.\n");
  11. }
  12. clearerr(stdin);
  13. if(ferror(stdin) > 0){
  14. printf("stdin error after clear.\n");
  15. }else if(feof(stdin) > 0){
  16. printf("stdin eof after clear.\n");
  17. }
  18. return 0;
  19. }

运行结果:

[email protected]:~/apue$ ./a.out
12345
12345   //ctrl+D
stdin eof.

从流中读取数据以后,可以调用ungetc将字符再压送回流中。

[cpp] view plaincopy

  1. #include <stdio.h>
  2. int ungetc(int c, FILE* fp);

压送回流中的字符以后又可以从流中读出,但是读出字符的顺序与压送回的顺序相反。回送的字符不必一定是上一次读取的字符,

不能回送EOF,但是已经到达文件尾端时,仍可以回送一字符。下次读将返回该字符,再次读则返回EOF。

该函数使用的场合是:当正在读一个输入流,并进行某种形式的分字或分记号操作,会经常用到回送字符操作。有时需要先看一下

下一个字符,以决定如何处理当前字符。然后就需要方便地将当看完的字符送回,以便下一次调用getc时返回该字符。如果标准

IO库不提供回送能力,就需要将该字符存放在一个我们自己的变量中,并设置一个标准以便判断在下一次需要一个字符时是调用

getc还是从我们自己的变量中取用。

实践:

[cpp] view plaincopy

  1. #include <stdio.h>
  2. int main(void){
  3. int c;
  4. if((c = fgetc(stdin)) != EOF){
  5. fputc(c,stdout);
  6. }
  7. ungetc(c,stdin);
  8. ungetc(c+1,stdin);
  9. while((c = fgetc(stdin)) != EOF){
  10. fputc(c,stdout);
  11. }
  12. printf("\n");
  13. return 0;
  14. }

运行结果:

[email protected]:~/apue$ ./a.out
a
aba

对应于上面所述的每个输入函数都有一个输出函数对应。

[cpp] view plaincopy

  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 plaincopy

  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 plaincopy

  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 plaincopy

  1. #include <stdio.h>
  2. int main(void){
  3. int result = 0;
  4. char buf[256];
  5. FILE* fp;
  6. if((fp = fopen("a.txt", "r+")) == NULL){
  7. result = -1;
  8. perror("fopen");
  9. goto FINALLY;
  10. }
  11. while(fgets(buf,256,fp) != NULL){
  12. fputs(buf,stdout);
  13. }
  14. FINALLY:
  15. if(fp != NULL){
  16. fclose(fp);
  17. }
  18. return result;
  19. }

运行结果:

[email protected]:~/apue$ cat a.txt
123
456
[email protected]:~/apue$ ./a.out
123
456

[email protected]:~/apue$

如果将上面的

[cpp] view plaincopy

  1. fputs(buf,stdout);

修改成

[cpp] view plaincopy

  1. puts(buf);

则结果为:

[email protected]:~/apue$ ./a.out
123

456

[email protected]:~/apue$

puts自动又将一个换行符写到标准输出。

3.二进制IO

下面2个函数执行二进制IO操作。

[cpp] view plaincopy

  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 plaincopy

  1. #include <stdio.h>
  2. int main(void){
  3. int result = 0;
  4. int data[10] = {0,1,2,3,4,5,6,7,8,9};
  5. int data2[10] = {0};
  6. FILE* fp;
  7. if((fp = fopen("bfile","wb+")) == NULL){
  8. result = -1;
  9. perror("fopen");
  10. goto FINALLY;
  11. }
  12. if(fwrite(&data[1], sizeof(int), 3, fp) < 0){  //写到文件
  13. result = -1;
  14. perror("fwrite");
  15. goto FINALLY;
  16. }
  17. fclose(fp);
  18. if((fp = fopen("bfile","rb+")) == NULL){
  19. result = -1;
  20. perror("fopen");
  21. goto FINALLY;
  22. }
  23. if(fread(data2, sizeof(int), 3, fp) < 0){   //从文件中读取 ,然后写到data2
  24. result = -1;
  25. perror("fread");
  26. goto FINALLY;
  27. }
  28. int i;
  29. for(i=0;i<10;i++){
  30. printf("i=%d:%d\n",i,data2[i]);
  31. }
  32. FINALLY:
  33. if(fp != NULL){
  34. fclose(fp);
  35. }
  36. return result;
  37. }

运行结果:

[email protected]:~/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 plaincopy

  1. #include <stdio.h>
  2. typedef struct{
  3. int a;
  4. char b;
  5. }myst;
  6. int main(void){
  7. int result = 0;
  8. FILE* fp;
  9. myst st1,st2;
  10. st1.a = 1;
  11. st1.b = ‘a‘;
  12. if((fp = fopen("bfile","wb+")) == NULL){
  13. result = -1;
  14. perror("fopen");
  15. goto FINALLY;
  16. }
  17. if(fwrite(&st1, sizeof(myst), 1, fp) < 0){
  18. result = -1;
  19. perror("fwrite");
  20. goto FINALLY;
  21. }
  22. fclose(fp);    //27到33行是必须的,,需要重新打开文件,,为什么需要重新打开呢.因为文件偏移量的原因??
  23. if((fp = fopen("bfile","rb+")) == NULL){
  24. result = -1;
  25. perror("fopen");
  26. goto FINALLY;
  27. }
  28. if(fread(&st2, sizeof(myst), 1, fp) < 0){
  29. result = -1;
  30. perror("fread");
  31. goto FINALLY;
  32. }
  33. printf("st2.a=%d\n",st2.a);
  34. printf("st2.b=%c\n",st2.b);
  35. FINALLY:
  36. if(fp != NULL){
  37. fclose(fp);
  38. }
  39. return result;
  40. }

运行结果:

[email protected]:~/apue$ ./a.out
st2.a=1
st2.b=a

时间: 2025-01-23 01:30:02

读和写流的相关文章

标准文件IO详解(五)---读和写流

C库函数中提供了三种不同类型的读写函数,这三种不同类型的读写方式如下: 一个字符一个字符的进行读写 以换行符为界一行一行的进行读写 一块一块的进行读写 ====================================================== 以字符为单位的读写函数: fgetc函数 和 fputc 函数 函数原型: 函数参数: stream:要操作的文件流指针 返回值: 调用成功时返回读取到的字符 调用失败时返回 EOF(-1) 读取到文件末尾时返回 EOF(-1) 注意:当

node中的可读流和可写流

javascript的一个不足之处是不能处理二进制数据,于是node中引入了Buffer类型.这个类型以一个字节(即8位)为单位,给数据分配存储空间.它的使用类似于Array,但是与Array又有不同:Buffer在定义的时候必须明确知道其长度,但是Array的长度是可以动态变化的.定义Buffer有三种方式: 1. var buf = new Buffer(3);//指定buffer占用3个字节 2. var buf = new Buffer("hello","utf-8&

多个流,简短的读和写

Boost::Asio中的许多I/O对象是流导向的,这意味着: @没有消息边界,在传输的数据是一个连续的字节序列 @读或者写传输的字节可能比请求更小,这就是被称作简短的读或者写 提供流定向模型的对象一个或者多个下列类型的必要条件: SyncReadStream,使用成员函数read_some()执行同步的读操作 AsyncReadStream,使用成员函数async_read_some() 执行异步读操作 SyncWriteStream, 使用成员函数write_some()执行一个同步的写操作

node.js 利用流实现读写同步,边读边写

//10个数 10个字节,每次读4b,写1b let fs=require("fs"); function pipe(source,target) { //先创建可读流,再创建可写流 //先读一次,rs.on(data) //将读到的类容写入目标中 ,返回布尔值,如果是ture,继续写,默认情况应该是false,暂停读取 //ws.on('drain'),抽干后,回复读取 //监听读取文件完毕后,关闭读取rs.on('end') let rs=fs.createReadStream(s

C#文件流的读与写

工作中遇到了文件的跨平台传送 运用了文件流 而且将计算机上的文件读取到程序内存里 反之将内存里的数据以文件的形式保存 都是比较常用的 在这里做一个简单的应用示例. 1 将内存数据“写”到计算机的文件里 const string path = @"D:\text.txt";//保存文件的路径 string content = "文件内容!!!!";//定义内存里的数据 byte[] bytes = Encoding.Default.GetBytes(content);

初识IO流——文本文件的读和写操作

1.想要实现文本文件的读和写操作,我们需要了解StreamWriter类和StreamReader类. StreamWriter是专门用来处理文本文件的类,可以方便地向文本文件中写入字符串.同时也负责重要的转换和处理向FileStream对象写入工作. StreamReader是专门用来读取文本文件的类,StreamReader可以从底层Stream对象创建StreamReader对象的实例,而且也能指定编码规范参数.创建StreamReader对象后,它提供了许多用于读取和浏览字符数据的方法.

java中文件的读与写

最近一直在学习java中如何读取和写出文件,看了java API之后,发现在java.io中有很多关于文件读与写的类,下面就介绍几个经常用到的. 首先是:InputStream和OutputStream,API中说它俩是所有抽象类表示字节输入输出流的超类,所以在它们下面派生了很多子类.例如:FileInputStream和OutputStream等等.这些类都是以单字节的形式读入数据的,所以如果读入的数据中有中文字符,那么就会出现中文乱码现象. 其次是:Reader和Writer,这两个类是用于

OpenCV下的CSV文件读、写

1.CSV文件格式简介 逗号分隔值(Comma-SeparatedValues,CSV,有时也称为字符分隔值,因为分隔字符也可以不是逗号),其文件以纯文本形式存储表格数据(数字和文本).纯文本意味着该文件是一个字符序列,不含必须像二进制数字那样被解读的数据.CSV文件由任意数目的记录组成,记录间以某种换行符分隔:每条记录由字段组成,字段间的分隔符是其它字符或字符串,最常见的是逗号或制表符.通常,所有记录都有完全相同的字段序列. CSV文件格式的通用标准并不存在,但是在RFC 4180中有基础性的

[Android L]SEAndroid开放设备文件结点权限(读或写)方法(涵盖常用操作:sys/xxx、proc/xxx、SystemProperties)

温馨提示 建议你先了解一下上一篇博文([Android L]SEAndroid增强Androd安全性背景概要及带来的影响)所讲的内容,先对SEAndroid窥个全貌,然后再继续本节内容. 1 现象描述 基于Android L版本源码环境进行开发时,根据项目需求,APP层需要操作sys/xxx 或 proc/xxx下面的文件结点,但是会报出以下权限异常,无法直接操作这些结点 LedLightFileUtil( 4671): java.io.FileNotFoundException: /sys/c