【C语言】标准IO

打印 上一主题 下一主题

主题 988|帖子 988|积分 2964


目次
1. 什么是标准IO
1.1概念
1.2特点
1.3 操纵
2. 缓存区
3. 函数接口
3.1打开文件fopen
3.2关闭文件
3.3读写文件操纵
3.3.1每次读写一个字符:fgetc()、fputc()
a. 针对文件
b. 针对终端
3.3.2 每次一串字符的读写fgets()和fputs()
c. 针对终端
d. 针对文件
3.1.3二进制读写fread()和fwrite()
a. 针对终端
b. 针对文件
3.4 其他操纵
3.4.1 重定向流到文件freopen
3.4.2 文件定位操纵


 



1. 什么标准IO

1.1概念

标准IO:在C库中定义的一组专门用于输入输出的函数。


1.2特点

(1) 通过缓冲机制减少系统调用,进步服从。
系统调用:内核向上提供的一组接口。
例如:从硬盘读1KB数据,每次只能读1B。


(2) 围绕着流(stream)进行操纵,流用FILE*来描述。


注意: vi用ctags索引使用:
1) vi -t 查找名称
输入前面序号,回车。
2) 继承追踪:
将光标定位到要追踪的内容,ctrl+]
回退:ctrl+t
3)跳转到上次位置:ctrl+o
跳转到下次位置:ctrl+i
(3) 标准IO默认打开三个流,sdtin(标准输入)、stdout(标准输出)、stderr(标准错误)流。
1.3 操纵

打开文件:fopen
关闭文件:fclose
读写操纵:fgetc、fputc、fgets、fputs、fread、fwrite
其他:freopen、rewind、fseek
2. 缓存区

(1)全缓存:和文件相关的
(2)行缓存:和终端相关
刷新缓存区的条件:
● \n
● 程序正常退出
● 逼迫刷新:fflush
● 缓存区满
  1. #include<stdio.h>
  2. int main(int argc, char const *argv[])
  3. {
  4.     // printf("hello world\n"); //\n不光换行还可以刷新缓存区,将缓存区内容刷新到终端。
  5.     printf("hello world");
  6.     fflush(NULL); //强制刷新缓存区
  7.     while(1);
  8.     return 0;
  9. }
复制代码
(3)不缓存,没有缓存,标准错误。
综上:当我们每次要打印数据时,并不是将数据直接发送给标准输出装备,也就是并直接发送给表现器,而是将要打印的数据先存放到缓存区,当缓冲存数据满时,或者遇到\n,或者程序结束时,或者手动刷新缓存区时,缓冲区才会把数据传输到标准输出装备中,也就是表现器中进行输出。
练习:盘算标准输出缓存区巨细KB
方法一:利用循环打印展示


方法二:利用结构体指针stdout(流指针FILE*类型)
  1. #include<stdio.h>
  2. int main(int argc, char const *argv[])
  3. {
  4.     printf("buf:"); //不进行输出的话缓存区不会开辟,所以要先加一句打印为了让标准IO开辟输出缓存区。
  5.     printf("%d\n",stdout->_IO_buf_end - stdout->_IO_buf_base);
  6.     return 0;
  7. }
复制代码
得到1024B
3. 函数接口

3.1打开文件fopen

  1. FILE *fopen(const char *path, const char *mode);
  2. 功能:打开文件
  3. 参数:
  4.     path:打开的文件路径
  5.     mode:打开的方式
  6.         r:只读,当文件不存在时报错,文件流定位到文件开头
  7.         r+:可读可写,当文件不存在时报错,文件流定位到文件开头
  8.         w:只写,文件不存在创建,存在则清空
  9.         w+:可读可写,文件不存在创建,存在则清空
  10.         a:追加(在末尾写),文件不存在创建,存在追加,文件流定位到文件末尾
  11.         a+:读和追加,文件不存在创建,存在追加,读文件流定位到文件开头,写文件流定位到文件末尾
  12. 注:当a+的方式打开文件时,写只能在末尾进行追加,定位操作是无法改变写的位置,但是可以改变读的位置
  13. 返回值:
  14.     成功:文件流
  15.     失败:NULL,并且会设置错误码
复制代码
3.2关闭文件

  1. int fclose(FILE *stream);
  2. 功能:关闭文件
  3. 参数:stream:文件流
复制代码
  1. #include <stdio.h>
  2. int main(int argc, char const *argv[])
  3. {
  4.     FILE *fp;
  5.     //1.打开文件
  6.     fp = fopen("test.c", "r");
  7.     if (NULL == fp)
  8.     {
  9.         perror("fopen err");
  10.         //while(1);//标准错误是不缓存,所以会直接显示到终端
  11.         return -1;
  12.     }
  13.     printf("fopen success\n");
  14.     //2. 关闭文件
  15.     fclose(fp);
  16.     return 0;
  17. }
复制代码
3.3读写文件操纵

3.3.1每次读写一个字符fgetc()fputc()

  1. 每次读一个字符fgetc()
  2.     int  fgetc(FILE * stream);
  3. 功能:从文件中读取一个字符,并将当前文件指针位置向后移动一个字符。
  4. 参数:stream:文件流
  5. 返回值:成功:读到的字符的ASCII
  6.        失败或读到文件末尾:EOF(-1)
  7.     每次写一个字符fputc()
  8.     int fputc(int c, FILE *stream);
  9. 功能:向文件中写入一个字符, 成功写入后文件指针会自动向后移动一个字节位置。
  10. 参数:c:要写的字符
  11.              stream:文件流
  12. 返回值:成功:写的字符的ASCII
  13.        失败:EOF(-1)
复制代码
a. 针对文件

  1. #include <stdio.h>
  2. int main(int argc, char const *argv[])
  3. {
  4.     FILE *fp;
  5.     char ch;
  6.     //打开文件
  7.     fp = fopen("test.c", "r+");
  8.     if (NULL == fp)
  9.     {
  10.         perror("fopen err");
  11.         return -1;
  12.     }
  13.     printf("fopen success\n");
  14.     //针对文件读写操作
  15.     //读操作
  16.     ch = fgetc(fp);
  17.     printf("%c %d\n", ch, ch); //h 104
  18.     ch = fgetc(fp);
  19.     printf("%c %d\n", ch, ch); //e 104
  20.     ch = fgetc(fp);
  21.     printf("%c %d\n", ch, ch); //l 108
  22.     //写操作
  23.     fputc('a', fp); //写个a(需要注意要有可写权限)
  24.     fputc(98, fp);  //写个b,此时文件中是helab
  25.     ch = fgetc(fp);
  26.     printf("%c %d\n", ch, ch); //EOF -1 (因为已经到末尾了)
  27.     //关闭文件
  28.     fclose(fp);
  29.     return 0;
  30. }
复制代码
b. 针对终端

  1. #include <stdio.h>
  2. int main(int argc, char const *argv[])
  3. {
  4.     char ch = fgetc(stdin);
  5.     printf("%c %d\n", ch, ch);
  6.     fputc('o', stdout);
  7.     fputc(10, stdout);
  8.     return 0;
  9. }
复制代码


补充feofferror
  1. int  feof(FILE * stream);
  2. 功能:判断文件有没有到结尾,也就是当前所在位置后面还有没有字符。
  3. 返回:如果到达文件末尾,返回非零值。如果后面还有字符则返回0。
复制代码
  1. #include <stdio.h>
  2. int main(int argc, char const *argv[])
  3. {
  4.     FILE *fp;
  5.     char ch;
  6.     //打开文件
  7.     fp = fopen("test.c", "r+");
  8.     if (NULL == fp)
  9.     {
  10.         perror("fopen err");
  11.         return -1;
  12.     }
  13.     printf("fopen success\n");
  14.     //针对文件读写操作
  15.     //读操作
  16.     ch = fgetc(fp);
  17.     printf("%c %d\n", ch, ch); //h 104
  18.     ch = fgetc(fp);
  19.     printf("%c %d\n", ch, ch); //e 104
  20.     ch = fgetc(fp);
  21.     printf("%c %d\n", ch, ch); //l 108
  22.     //写操作
  23.     fputc('a', fp); //写个a(需要注意要有可写权限)
  24.     fputc(98, fp);  //写个b,此时文件中是helab
  25.     //前面和之前例子一样,然后判断是否末尾
  26.     if (feof(fp))
  27.     {
  28.         printf("end1\n");   //因为后面还有一个EOF,所以判断末尾不成功。不会打印end1。
  29.         return -1;
  30.     }
  31.     ch = fgetc(fp);
  32.     printf("%c %d\n", ch, ch); //EOF -1
  33.     if (feof(fp))
  34.     {
  35.         printf("end2\n");    //会打印出来,因为后面没有内容,已经到末尾了。
  36.         return -1;
  37.     }
  38.     //关闭文件
  39.     fclose(fp);
  40.     return 0;
  41. }
复制代码


  1. int ferror(FILE * stream);
  2. 功能:检测文件有没有出错
  3. 返回:文件出错,返回非零值。如果没有出错,返回0。
复制代码
  1. #include <stdio.h>
  2. int main(int argc, char const *argv[])
  3. {
  4.     FILE *fp;
  5.     char ch;
  6.     //打开文件
  7.     fp = fopen("test.c", "w");
  8.     if (NULL == fp)
  9.     {
  10.         perror("fopen err");
  11.         return -1;
  12.     }
  13.     printf("fopen success\n");
  14.     //因为权限为只写,所以读操作有错误。
  15.     ch = fgetc(fp);
  16.     if (ferror(fp))
  17.     {
  18.         printf("err exist\n");
  19.         return -1;
  20.     }
  21.     //关闭文件
  22.     fclose(fp);
  23.     return 0;
  24. }
复制代码
练习:cat 文件名
  1. #include <stdio.h>
  2. /* cat 文件名:查看文件内容,显示到终端。
  3.    步骤:1.打开文件
  4.         2.循环用fgetc获取文件内容
  5.         3.当读到文件末尾标志EOF时结束
  6.         4.将读取文件内容用fputc打印到终端
  7.         5.关闭文件
  8. */
  9. int main(int argc, char const *argv[])
  10. {
  11.     char ch;
  12.     if (argc != 2)
  13.     {
  14.         printf("pls input %s <filename>\n", argv[0]);
  15.         return -1;
  16.     }
  17.     //1. 打开文件
  18.     FILE *fp = fopen(argv[1], "r");
  19.     if (NULL == fp)
  20.     {
  21.         perror("fopen err");
  22.         return -1;
  23.     }
  24.     //2. 循环用fgetc获取文件内容
  25.     //3. 当读到文件末尾标志EOF时结束
  26.     while ((ch = fgetc(fp)) != EOF) //当读到内容不是EOF就进入循环
  27.     {
  28.         //4.将读到内容用fputc打印到终端
  29.         fputc(ch, stdout);
  30.     }
  31.     //5. 关闭文件
  32.     return 0;
  33. }
复制代码
3.3.2 每次一串字符的读写fgets()和fputs()

  1. char * fgets(char *s,  int size,  FILE * stream);
  2. 功能:从文件中每次读取一行字符串
  3. 参数:    s:存放字符串的地址
  4.          size:一次读取的字符个数
  5.          stream:文件流
  6. 返回值:成功:s的地址
  7.        失败或读到文件末尾:NULL
  8. 特性:  每次实际读取的字符个数为size-1个,会在末尾自动添加\0
  9.        每次读一行,遇到\n或者到达文件末尾后不再继续读下一行
  10.        并把它存储在s所指向的字符串内。
  11.       
  12. int fputs(const char *s, FILE *stream);
  13. 功能:向文件中写字符串
  14. 参数:s:要写的内容
  15.      stream:文件流
  16. 返回值:成功:非负整数
  17.        失败:EOF
复制代码
c. 针对终端

  1. #include <stdio.h>
  2. int main(int argc, char const *argv[])
  3. {
  4.     char buf[32]="";
  5.     //针对终端
  6.     //输入操作
  7.     fgets(buf,sizeof(buf),stdin); //终端输入的是hello\n
  8.     printf("buf:%s\n",buf); //此时buf里面存的内容是hello\n\0
  9.     //输出操作
  10.     fputs(buf,stdout);      //把buf中的内容hello\n\0输出到终端
  11.     fputs("world",stdout);  //输出world\0到终端
  12.     return 0;
  13. }
复制代码
注意:一定会留一个位置给\0
d. 针对文件

  1. #include <stdio.h>
  2. int main(int argc, char const *argv[])
  3. {
  4.     char buf[32] = "";
  5.     //打开文件
  6.     FILE *fp = fopen("test.c", "r+");
  7.     if (NULL == fp)
  8.     {
  9.         perror("fopen err");
  10.         return -1;
  11.     }
  12.     printf("fopen success\n");
  13.     //针对文件读写操作
  14.     //读操作
  15.     fgets(buf, 32, fp); //hello\n\0
  16.     fputs(buf, stdout);
  17.     fgets(buf, 32, fp); //world\n\0
  18.     fputs(buf, stdout);
  19.     fgets(buf, 32, fp); //hahaha\0
  20.     fputs(buf, stdout);
  21.     fputs("666",fp);    //向文件写666\0
  22.     //关闭文件
  23.     fclose(fp);
  24.     return 0;
  25. }
复制代码
注意:如果到达末端则返回NULL,继承输出的还是上一次buf中生存的内容。
练习:通过fgets实现"wc -l 文件名"命令功能(盘算文件行数)
思路:打开文件,循环读文件fgets(buf,32,fp);
  1. #include <stdio.h>
  2. #include <string.h>
  3. int main(int argc, char const *argv[])
  4. {
  5.     char buf[32] = "";
  6.     int n=0;
  7.     if(argc!=2)
  8.     {
  9.         printf("pls input:%s <filename>\n",argv[0]);
  10.         return -1;
  11.     }
  12.     FILE *fp = fopen(argv[1], "r");
  13.     if (NULL == fp)
  14.     {
  15.         perror("fopen err");
  16.         return -1;
  17.     }
  18.     printf("fopen success\n");
  19.     while (fgets(buf,32,fp)!=NULL)
  20.     {
  21.         if(buf[strlen(buf)-1]=='\n')
  22.             n++;
  23.     }
  24.     printf("%d %s\n",n,argv[1]);
  25.     fclose(fp);
  26.     return 0;
  27. }
复制代码
注意:wc-l也会少一行,因为末了一行没有换行
3.1.3二进制读写fread()fwrite()

  1. size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
  2. 功能:从文件流读取多个元素(将二进制数据从文件读出)
  3.     参数:  ptr :是一个指针,是存放数据的存储空间的起始地址,用来存放读取元素
  4.        size :元素大小  sizeof(元素数据类型)
  5.     nmemb :读取元素的个数
  6.        stream :要读取的文件流
  7. 返回值:成功:读取的元素的个数
  8.        读到文件尾或失败: 0
  9.     size_t fwrite(const void *ptr, size_t size, size_t nmemb,
  10.               FILE *stream);
  11. 功能:将二进制数据写入文件
  12. 参数: ptr :是一个指针,保存要输出数据的空间的地址。
  13.      size :要写入的字节数 sizeof(数据类型)
  14.     nmemb : 要进行写入元素的个数
  15.       strem: 目标文件流指针
  16. 返回值:成功:写的元素个数
  17.               失败 :-1
复制代码
a. 针对终端

  1. char buf[32];
  2. fread(buf,1,10,stdin);
  3. printf("%s\n",buf);
  4. fwrite(buf,1,10,stdout);
复制代码


因为读写了10个单元char类型元素
b. 针对文件

  1. #include <stdio.h>
  2. #include <string.h>
  3. int main(int argc, char const *argv[])
  4. {
  5.     FILE *fp;
  6.     float arr[3]={1.2,2.3,3.4};
  7.     float data[3]={0};
  8.     fp=fopen(argv[1],"r+");
  9.     if (fp==NULL)
  10.     {
  11.         perror("err");
  12.         return -1;
  13.     }
  14.     fwrite(arr,4,3,fp);
  15.     rewind(fp);//定位到文件开头
  16.     fread(data,4,3,fp);
  17.     printf("%f %f %f\n",data[0],data[1],data[2]);
  18.     return 0;
  19. }
复制代码
文件定位操纵:rewind(FILE *fp);

练习:
2. 标题要求:编程读写一个文件test.txt,每隔1秒向文件中写入一行录入时间的数据,类似这样:
1, 2007-7-30 15:16:42
2, 2007-7-30 15:16:43
该程序应该无穷循环,直到按Ctrl-C中断程序。
再次启动程序写文件时可以追加到原文件之后,并且序号能够接续上次的序号,比如:
1, 2007-7-30 15:16:42
2, 2007-7-30 15:16:43
3, 2007-7-30 15:19:02
4, 2007-7-30 15:19:03
5, 2007-7-30 15:19:04
思路:
1. 打开文件fopen,循环往文件写内容
2. 每隔1s写入一行,sleep(1);
3. 盘算文件行数,wc -l
4. 盘算当前时间,转换成年月日、时分秒,time,localtime
man 2 time
time_t time(time_t *t);
如果t是空指针,直接返回当前时间。如果t不是空指针,返回当前时间的同时,将返回值赋予t指向的内存空间。
5. 字符串拼接函数:strcpy/strcat(dest, src)、sprintf、fprintf
fprintf:
格式化输出到流(stream)文件中,返回值是输出的字符数,发生错误时返回一个负值.
int fprintf( FILE *stream, const char *format, ... );
sprintf:
格式化输出发送到buffer(缓冲区)中.返回值是写入的字符数量.
int sprintf( char *buffer, const char *format, ... );
思路:
FILE *fp = fopen();
//盘算文件行数
while(fgets()!=NULL)
if(buf[] == '\n')
n++;
//往文件中写入内容
while(1)
{
//盘算时间
time_t t = time();
struct tm *tm = localtime(t);
fprintf(fp, "%d,%d");
sleep(1);
}
  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <time.h>
  4. #include <unistd.h>
  5. int main(int argc, char const *argv[])
  6. {
  7.     FILE *fp;
  8.     char buf[32] = "";
  9.     int n = 0;
  10.     time_t t;
  11.     struct tm *tm;
  12.     fp = fopen(argv[1], "a+");
  13.     if (NULL == fp)
  14.     {
  15.         perror("fopen err");
  16.         return -1;
  17.     }
  18.     while (fgets(buf, 32, fp) != NULL)
  19.     {
  20.         if (buf[strlen(buf) - 1] == '\n')
  21.             n++;
  22.     }
  23.     while (1)
  24.     {
  25.         time(&t); //t=time(NULL);
  26.         tm = localtime(&t);
  27.         fprintf(fp, "%d,%d-%d-%d %d:%d:%d\n", ++n, tm->tm_year + 1900,
  28.                 tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); //月份从1月开始,tm结构体中月份是0-11所以+1
  29.         fflush(NULL); //全缓存,写文件里面没有\n刷新,所以要手动刷新。
  30.         sleep(1);
  31.     }
  32.     fclose(fp);
  33.     return 0;
  34. }
复制代码
3.4 其他操纵

3.4.1 重定向流到文件freopen

freopen()用于将指定的流重定向到打开的文件
  1. FILE *freopen(const char *path, const char *mode, FILE *stream);
  2. 功能:将指定的文件流重定向到打开的文件中
  3. 参数:path:文件路径
  4.      mode:打开文件的方式(同fopen)
  5.      fp:文件流指针
  6. 返回值:成功:返回文件流指针
  7.        失败:NULL
复制代码
  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <time.h>
  4. #include <unistd.h>
  5. int main(int argc, char const *argv[])
  6. {
  7.     printf("hello\n");
  8.     //将标准输出流重定向到打开的test.txt文件中
  9.     freopen("test.txt","w+",stdout);
  10.     printf("world\n");
  11.     //将标准输出流重新重定向到终端文件/dev/tty
  12.     freopen("/dev/tty","r+",stdout);
  13.     printf("hahaha\n");
  14.     return 0;
  15. }
复制代码
3.4.2 文件定位操纵

  1. void rewind(FILE *stream);
  2. 功能:将文件位置指针定位到起始位置
  3. int fseek(FILE *stream, long offset, int whence);
  4. 功能:文件的定位操作
  5. 参数:stream:文件流
  6.      offset:偏移量:正数表示向后文件尾部偏移,负数表示向文件开头偏移
  7.      whence:相对位置:
  8.            SEEK_SET:相对于文件开头
  9.            SEEK_CUR:相对于文件当前位置
  10.            SEEK_END:相对于文件末尾
  11. 返回值:成功:0
  12.        失败:-1   
  13.                注:当打开文件的方式为a或a+时,fseek不起作用     
  14. 补充:其中SEEK_SET,SEEK_CUR和SEEK_END和依次为0,1和2.
  15.                简言之:
  16. fseek(fp,100,0); 把fp指针移动到离文件开头100字节处.
  17.                fseek(fp,100,1); 把fp指针移动到离文件当前位置100字节处;
  18. ffseek(fp,-100,2);把fp指针退回到离文件结尾100字节处。
  19. long ftell(FILE *stream);
  20. 功能:获取当前的文件位置
  21. 参数:要检测的文件流
  22. 返回值:成功:当前的文件位置,出错:-1
复制代码
  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <time.h>
  4. #include <unistd.h>
  5. int main(int argc, char const *argv[])
  6. {
  7.     FILE *fp = fopen("test.txt","w+");
  8.     if (NULL==fp)
  9.     {
  10.         perror("err");
  11.         return -1;
  12.     }
  13.     //相对于开头往后10个,写一个a
  14.     fseek(fp,10,SEEK_SET);
  15.     fputc('a',fp);
  16.     //相等于当前位置往后5个,写一个hello
  17.     fseek(fp,5,SEEK_CUR);
  18.     fputs("hello",fp);
  19.     //想对于最后往前1个,写一个i
  20.     fseek(fp,-1,SEEK_END);
  21.     fputc('i',fp);
  22.     long l = ftell(fp); //计算文件位置指针所在位置
  23.     printf("%ld\n",l);  //21
  24.     return 0;
  25. }
复制代码


笔试题:
1. 想对一个文本文件的尾部追加写入,应当在fopen何中使用的文件操纵方式指示符号为 ()(杭州快越科技笔试题)
A. r B.wb C. a D.w+
2. fseek(1, 2, 3); 这个函数是什么作用,三个参数分别是什么意思?(深圳元征信息科技)
3. 函数调用语句:fseek (fp,-10L,2);的含义是
A 将文件位置指针从文件未尾处向文件头的方向移动10个字节
B 将文件位置指针从当前位置向文件头的方向移动10个字节
C 将文件位置指针从当前位置向文件未尾方向移动10个字节

总结:为什么用标准IO?
1. 因为读写文件通常是大量的数据,这时使用标准IO可以大大减少系统调用的次数,从而进步服从。
2. 为了保证可移植性
关于缓存区: 库函数的缓冲区对于库函数,如果标准输出连到终端装备(直接输出到屏幕),则它是行缓冲的(遇到回车换行符或者是缓冲区满了才输出);否则(输出到文件)是全缓冲的(缓冲区填满或者是程序运行结束了才输出)。程序运行结束时,会刷新所有的缓冲区。



免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

耶耶耶耶耶

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表