目录
一、思维导图
二、今日知识回顾
2.1 缓冲区
1. 只有标准IO才有缓冲区,所有的数据都先放在缓冲区种,缓冲区满或者满足一定条件后刷新缓冲区。
2.在实际生活生产中,我们的代码会运行在死循环中,导致缓冲区可能不满且程序没有退出。所以必须掌握刷新缓冲区的条件。
2.1.1 全缓冲
(1)操作对象
- 手动用fopen打开文件后,创建的缓冲区都是全缓冲。用FILE*类型流指针进行维护。
(2)大小
- 4096bytes=4k
//由于编译器优化,只打开不操作,此时不会真正申请缓冲区。
fputc('a', fp);
printf("%ld\n", fp->_IO_buf_end - fp->_IO_buf_base );
(3)刷新条件(6种):
- 1> 缓冲区满 (要多写一个后才能刷新前4096个)
- 2> fflush函数,强制刷新输出流缓冲区;
#include <stdio.h>
int fflush(FILE *stream);
- 3> 关闭流指针 fclose
- 4> 主函数调用return
- 5> 调用exit函数退出程序
功能:目前只要理解能退出程序即可;
原型:
#include <stdlib.h>
void exit(int status);
参数:
int status:目前随便填一个int类型整数即可,例如 1 2 0
- 6> 输入输出转换
- 7> ...
(4)代码验证:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, const char *argv[])
{
//以写的方式打开文件
FILE* fp = fopen("./fullBuf.txt","w");
if(NULL == fp)
{
perror("fopen");
return -1;
}
//输入单字符
fputc('a',fp);
fputc('b',fp);
fputc('c',fp);
printf("%ld\n",fp->_IO_buf_end - fp->_IO_buf_base);//打印全缓冲区的大小
fflush(fp);//刷新缓冲区
while(1)
{}
//关闭流指针
fclose(fp);
return 0;
}
2.1.2 行缓冲
(1)操作对象
- 标准输入流指针(FILE* stdin) 标准输出流指针(FILE* stdout)
(2)大小
- 1024bytes = 1k
printf("size=%ld\n", stdout->_IO_buf_end - stdout->_IO_buf_base);
(3)刷新条件(7种):
- 1> 缓冲区满 (要多写一个后才能刷新前1024个)
- 2> fflush函数,强制刷新输出流缓冲区;
#include <stdio.h>
int fflush(FILE *stream);
- 3> 关闭流指针 fclose
- 4> 主函数调用return
- 5> 调用exit函数退出程序
功能:目前只要理解能退出程序即可;
原型:
#include <stdlib.h>
void exit(int status);
参数:
int status:目前随便填一个int类型整数即可,例如 1 2 0
- 6> 遇到\n字符
- 7> 输入输出转换
(4)代码验证:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, const char *argv[])
{
//stdin stdout stderr
char s1[20]="";
scanf("%s", s1);
printf("s1=%s\n", s1);
char s2[20]="";
fscanf(stdin,"%s", s2);
fprintf(stdout,"s2=%s\n", s2);
printf("stdin的size为%ld\n", stdin->_IO_buf_end - stdin->_IO_buf_base);
printf("stdout的size为%ld\n", stdout->_IO_buf_end - stdout->_IO_buf_base);
printf("stderr的size为%ld\n", stderr->_IO_buf_end - stderr->_IO_buf_base);
return 0;
}
2.1.3 无缓冲
(1)操作对象
- 标准错误输出流指针(FILE* stderr) -->perror函数默认分装的就是stderr流指针。
(2)大小
- 1bytes,且只要往里放数据,就会直接将数据刷新出来。
(3)刷新条件:无
(4)代码验证
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, const char *argv[])
{
/*
//查看无缓冲区的大小:
fputc('b',stderr);
printf("size=%ld\n", stderr->_IO_buf_end - stderr->_IO_buf_base);
*/
fputc('b',stderr);
perror("aaaaa");
return 0;
}
三、课堂习题
3.1 用fgets从文件中获取字符并打印到终端
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, const char *argv[])
{
//打开文件,以读的方式
FILE* fp=fopen("./01_open.c","r");
if(NULL==fp)
{
perror("fopen");
return -1;
}
char s1[20]="";
while(1)
{
bzero(s1,sizeof(s1));
if(fgets(s1,sizeof(s1), fp)==NULL)
{
break;
}
printf("%s", s1);
}
return 0;
}
3.2 用fgetc与fputc函数实现文件拷贝
#include <stdio.h>
#include <head.h>
int main(int argc, const char *argv[])
{
//以读的形式打开文件1
FILE* fp_r=fopen("./02_fprintf.c","r");
if(NULL == fp_r)
{
ERR_MSG("fopen");
return -1;
}
//以写的形式打开文件2
FILE* fp_w=fopen("./2.txt","w");
if(NULL == fp_w)
{
ERR_MSG("fopen");
return -1;
}
//读一次写一次
char bf[128]="";
while(1)
{
bzero(bf,sizeof(bf));
if(fgets(bf,sizeof(bf),fp_r)==NULL)
break;
fputs(bf,fp_w);
}
printf("拷贝成功\n");
//关闭文件
if(fclose(fp_r)<0)
{
ERR_MSG("fclose");
return -1;
}
if(fclose(fp_w)<0)
{
ERR_MSG("fclose");
return -1;
}
return 0;
}
3.3 用fgets计算一个文件有几个字符
#include <stdio.h>
#include <head.h>
int main(int argc, const char *argv[])
{
FILE* fp=fopen("./01_open.c","r");
if(NULL ==fp)
{
ERR_MSG("fopen");
return -1;
}
//循环读数
char str[2]="";
int count=0;
while(1)
{
if(fgets(str,sizeof(str),fp)==NULL)
break;
count+=strlen(str);
}
printf("count = %d\n",count);
if(fclose(fp)<0)
{
ERR_MSG("fclose");
}
return 0;
}
3.4 fgets的选择题
在文件中有如下数据:123456789 选(AD)
char str[9]; fgets(str, 10, fp); printf("str=%s", str);
A. 123456789 B.123456789乱码 C.12345678 D.段错误
3.5 用fwrite将结构体写进文件中
#include <stdio.h>
#include <head.h>
typedef struct Car
{
char name[10];
int price;
}_C;
int main(int argc, const char *argv[])
{
FILE* fp=fopen("fwrite.txt","w");
if(NULL==fp)
{
ERR_MSG("fopen");
return -1;
}
_C car;
strcpy(car.name,"大众");
car.price=1000;
size_t res=0;
res = fwrite(&car,sizeof(_C),1,fp);
printf("size=%ld\n",res);
_C p[3]={"xjj",20,"xyt",20,"xjx",20};
res =fwrite(p,sizeof(_C),3,fp);
printf("size=%ld\n",res);
if(fclose(fp)<0)
{
ERR_MSG("fclose");
return -1;
}
return 0;
}
3.6 用fread将文件中的结构体读取到终端打印
#include <stdio.h>
#include <head.h>
//用fread将文件中的结构体读取到终端打印
typedef struct Car
{
char name[10];
int price;
}_C;
int main(int argc, const char *argv[])
{
FILE* fp=fopen("fwrite.txt","r");
if(NULL==fp)
{
ERR_MSG("fopen");
return -1;
}
_C car;
size_t res=0;
while(1)
{
memset(&car,0,sizeof(car));
//一次读取一个_C类型的结构体数据,直到读完为止
res = fread(&car,sizeof(_C),1,fp);
if(0 == res)
break;
printf("res=%ld %s %d\n",res, car.name, car.price);
}
if(fclose(fp)<0)
{
ERR_MSG("fclose");
return -1;
}
return 0;
}
3.7 用fseek调整光标位置
#include <stdio.h>
#include <head.h>
int main(int argc, const char *argv[])
{
//用fseek调整光标位置
FILE* fp=fopen("fseek.txt","w+");
if(NULL==fp)
{
ERR_MSG("fopen");
return -1;
}
fputc('A',fp);
fputc('B',fp);
fputc('C',fp);
int rec = fseek(fp,0,SEEK_SET);
printf("rec = %d\n",rec);
int c = 0;
rec = fseek(fp,-1,SEEK_SET);
printf("rec = %d\n",rec);
if(fclose(fp)<0)
{
ERR_MSG("fclose");
return -1;
}
return 0;
}
四、作业
4.1 使用fgets实现计算一个文件有几行
#include <stdio.h>
#include <head.h>
int main(int argc, const char *argv[])
{
//以读的方式打开文件
FILE* fp=fopen("./01_open.c","r");
if(NULL==fopen)
{
ERR_MSG("fopen");
return -1;
}
//循环读数
char str[2]="";
int count=0;
int line=0,i=0;
while(1)
{
//循环获取fp指针指向的文件中的数据,直至没有数据
if(fgets(str,sizeof(str),fp)==NULL)
break;
//计算个数
count+=strlen(str);
//计算行数
for(i=0;i<2;i++)
{
if(str[i]=='\n')
{
line++;
}
}
}
//打印个数、行数
printf("count = %d\nline = %d\n",count,line);
//关闭文件
if(fclose(fp)<0)
{
ERR_MSG("fclose");
return -1;
}
return 0;
}
4.2 用fread和fwrite实现文件拷贝
方法一:
#include <stdio.h>
#include <head.h>
int main(int argc, const char *argv[])
{
//用fread和fwrite实现文件拷贝
//以读的方式打开文件1
FILE* fp_r=fopen("./01_open.c","r");
if(NULL == fp_r)
{
ERR_MSG("fopen");
return -1;
}
//以写的方式打开文件2
FILE* fp_w=fopen("./2.txt","w");
if(NULL == fp_w)
{
ERR_MSG("fopen");
return -1;
}
//循环读取文件1中的字符并写到文件2中,直至文件1字符结束
char a=0;
int rec=0;
while(1)
{
if(fread(&a,sizeof(a),1,fp_r)==0)
break;
fwrite(&a,sizeof(a),1,fp_w);
}
//关闭文件1
if(fclose(fp_r)<0)
{
ERR_MSG("fclose");
return -1;
}
//关闭文件2
if(fclose(fp_w)<0)
{
ERR_MSG("fclose");
return -1;
}
return 0;
}
方法二:
#include <stdio.h>
#include <head.h>
int main(int argc, const char *argv[])
{
FILE* fp_r = fopen("./02_fprintf.c","r");
if(NULL == fp_r)
{
ERR_MSG("fopen");
return -1;
}
FILE* fp_w = fopen("./2.txt","w");
if(NULL == fp_w)
{
ERR_MSG("fopen");
return -1;
}
char buf[128]= "";
size_t res=0;
while(1)
{
bzero(buf,sizeof(buf));
res=fread(buf, 1, sizeof(buf), fp_r);
if(0 == res)
break;
fwrite(buf, 1, res, fp_w);
}
printf("拷贝完毕\n");
fclose(fp_r);
fclose(fp_w);
return 0;
}
4.3 封装自定义库函数head.h
/usr/include/head.h
#ifndef __HEAD_H__
#define __HEAD_H__
#include <string.h>
#include <unistd.h>
#define ERR_MSG(msg) do{\
fprintf(stderr,"__%d__",__LINE__); \
perror(msg);\
}while(0);
#endif