1.IO
IO指的是input/output,其操作的对象是文件,而在Linux系统中一切皆是文件。
2.文件
文件是一段数据的集合,通常存放在外存中,掉电后数据不会丢失。
2.1文件的分类
1)b(block,块设备文件)(文件IO):按块扫描信息的文件,称为块设备文件。通常存储类型的设备通常为块设备文件。
2)c(character,字符设备文件)(文件IO): 按字符扫描信息的文件,称为字符设备文件。一般设备通常为字符设备文件。
3)d(directory,目录文件) (目录IO/文件IO):目录文件,存放文件的文件夹。
4)-(普通文件)(标准IO/文件IO): 存放信息的文件。
5)l(link,链接文件)(链接IO/文件IO): 操作文件等价于操作文件指向的文件。
6)s(socket,套接字文件) (文件IO):用来进程间通信。
7)p(pipe,管道文件) (文件IO):用来进程间通信。
3.标准IO
标准IO通常用来操作普通文件。
3.1普通文件类型
ASCII码文件:文件中的所有内容均为能够在屏幕上显示的ASCII码字符。程序、文本文件均为ASCII码文件
二进制文件:文件中的所有内容均为数据对应的二进制形式存放(包含一些不能在界面上显示的内 容)。ASCII码文件也是二进制文件。图片、音视频、压缩包均为二进制文件
3.2标准IO接口
1. fopen/fclose
2. fgetc/fputc
3. fgets/fputs
4. fscanf/fprintf
5. fread/fwrite
6. fseek/rewind/ftell
所有文件操作步骤均为:1)打开文件 2)读写文件 3)关闭文件。
3.3文件的打开
3.3.1在文件运行时已经打开的三个特殊的流
stdin:标准输入流,scanf、gets、getchar都是通过stdin流实现获得终端信息。
stdout:标准输出流,printf、puts、putchar都是通过stdout流实现在终端信息打印。
stderr:标准出错流,perror通过stderr流实现在终端打印出错信息。
#include <stdio.h>
#include <errno.h>
#include <string.h>
int main(void)
{
FILE *fp = NULL;
fp = fopen("a.txt", "w");//打开
if (NULL == fp)
{
perror("fail to fopen");
return -1;
}
//写入
fclose(stdout);
printf("hello world!\\n");
fclose(stdin);
getchar();
fclose(stderr);errno = 2;
perror("hello world\\n");
return 0;
}
关掉stdin,stdout,stderr流后不会执行相关语句
3.3.2函数接口
3.3.2.1fopen打开文件
原型:FILE *fopen(const char *pathname, const char *mode);
功能:
打开pathname指向字符串对应的文件,并且和它建立一个流
参数:
pathname:要打开的文件路径字符串
mode:打开的方式
r 只读 文件存在只读打开,文件不存在报错
r+ 读写 文件存在读写打开,文件不存在报错
w 只写 文件存在清0,文件不存在创建,只写打开
w+ 写读 文件存在清0,文件不存在创建,写读打开
a 追加 文件存在追加,文件不存在创建,只写打开
a+ 追加读写 文件存在追加,文件不存在创建,写读打开
返回值:
成功返回FILE*指针
失败返回NULL
3.3.2.2fclose关闭文件
原型:int fclose(FILE *stream);
功能:
关闭已经打开的流
参数:
stream:文件流指针
返回值:
成功返回0,失败返回EOF(-1)
3.3.2.3fputc向文件写入单个字符
原型:int fputc(int c, FILE *stream);
功能:
将字符c写入流中
参数:
c:要写入的字符
stream:文件流指针
返回值:
成功返回输出的ASCII码值
失败返回EOF
向文件中写入hello world
#include <stdio.h>
#include <errno.h>
#include <string.h>
int main(void)
{
FILE *fp = NULL;
fp = fopen("a.txt", "w");//打开
if (NULL == fp)
{
perror("fail to fopen");
return -1;
}
//写入
fputc('h',fp);
fputc('e',fp);
fputc('l',fp);
fputc('l',fp);
fputc('o',fp);
fputc(' ',fp);
fputc('w',fp);
fputc('o',fp);
fputc('r',fp);
fputc('l',fp);
fputc('d',fp);
fclose(fp);//关闭
return 0;
}
也可以定义一个指针指向数组循环写入:
#include <stdio.h>
#include <errno.h>
#include <string.h>
int main(void)
{
FILE *fp = NULL;
char str[] = {"hello world123"};
char *pstr = NULL;
pstr = str;
fp = fopen("a.txt", "w");//打开
if (NULL == fp)
{
perror("fail to fopen");
return -1;
}
//写入
while(*pstr != '\\0')
{
fputc(*pstr,fp);
pstr++;
}
fclose(fp);//关闭
return 0;
}
3.3.2.4fgetc读取文件中的所有字符
原型:int fgetc(FILE *stream);
功能:
读取流中的下一个字符
参数:
stream:文件流指针
返回值:
成功返回读到字符的ASCII码值
失败或者读到文件末尾返回EOF
将文件中的内容读取并打印:
#include <stdio.h>
#include <errno.h>
#include <string.h>
int main(void)
{
FILE *fp = NULL;
char ch = 0;
fp = fopen("a.txt", "r");//打开
if (NULL == fp)
{
perror("fail to fopen");
return -1;
}
//打印
while(1)
{
ch = fgetc(fp);
if(ch == EOF)
{
break;
}
printf("%c",ch);
}
fclose(fp);//关闭
return 0;
}
统计文件的行数:
#include <stdio.h>
#include <errno.h>
#include <string.h>
int main(void)
{
FILE *fp = NULL;
char ch = 0;
int cont = 1;
fp = fopen("a.txt", "r");//打开
if (NULL == fp)
{
perror("fail to fopen");
return -1;
}
//统计
while(1)
{
ch = fgetc(fp);
if(ch == EOF)
{
break;
}
if(ch == '\\n')
{
cont++;
}
}
printf("该文件有%d行",cont);
fclose(fp);//关闭
return 0;
}
也可以封装函数达到相同统计行数效果:
#include <stdio.h>
int get_line(char *pfile)//
{
int cnt = 1;
FILE *fp = NULL;
char ch = 0;
fp = fopen(pfile, "r");//传递过来的是指针,打开指针所指的文件名,不能用(“pfile”,"r")打开,这样是打开叫pfile的文件
if (NULL == fp)
{
perror("fail to fopen");
return -1;
}
while (1)
{
ch = fgetc(fp);
if (EOF == ch)
{
break;
}
if ('\\n' == ch)
{
cnt++;
}
}
fclose(fp);
return cnt;
}
int main(void)
{
char filepath[256] = {0};
int line = 0;
printf("请输入文件名:\\n");
gets(filepath);
line = get_line(filepath);
printf("行数:%d\\n", line);
return 0;
}
将a.txt拷贝到b.txt中:
#include <stdio.h>
#include <errno.h>
#include <string.h>
int main(void)
{
FILE *fp1 = NULL;
FILE *fp2 = NULL;
char ch = 0;
fp1 = fopen("a.txt", "r");//只读打开a
fp2 = fopen("b.txt", "w");//只写打开b
if (NULL == fp1)
{
perror("fail to fopen");
return -1;
}
if (NULL == fp2)
{
perror("fail to fopen");
return -1;
}
//拷贝
while(1)
{
ch = fgetc(fp1);
if(ch == EOF)
{
break;
}
fputc(ch,fp2);//变量不用加单引号
}
fclose(fp1);//关闭
fclose(fp2);
return 0;
}
将其封装达成相同拷贝效果:
#include <stdio.h>
void copy_file_content(char *pdstfile, char *psrcfile)
{
FILE *fsrc = NULL;
FILE *fdst = NULL;
char ch = 0;
fsrc = fopen(psrcfile, "r");
if (NULL == fsrc)
{
perror("fail to fopen");
return;
}
fdst = fopen(pdstfile, "w");
if (NULL == fdst)
{
perror("fail to fopen");
return;
}
while (1)
{
ch = fgetc(fsrc);
if (EOF == ch)
{
break;
}
fputc(ch, fdst);
}
fclose(fsrc);
fclose(fdst);
return;
}
int main(void)
{
char srcfile[256] = {0};
char dstfile[256] = {0};
printf("请输入源文件:\\n");
gets(srcfile);
printf("请输入目的文件:\\n");
gets(dstfile);
copy_file_content(dstfile, srcfile);
printf("拷贝完成\\n");
return 0;
}
统计文件中出现最多的字符,输出改=该字符及其数量:
#include <stdio.h>
#include <errno.h>
#include <string.h>
int main(void)
{
FILE *fp = NULL;
char ch = 0;
char zifuchuan[1024] = {0};
int cnt[256]={0};
int max = 0;
fp = fopen("a.txt", "r");//打开
if (NULL == fp)
{
perror("fail to fopen");
return -1;
}
//统计
//fgets
while(fgets(zifuchuan, sizeof(zifuchuan), fp) != NULL)
{
for (int i = 0; zifuchuan[i] != '\\0'; i++)
{
ch = zifuchuan[i];
cnt[ch]++;
}
}
#if 0//fgetc
while(1)
{
ch = fgetc(fp);
if(ch == EOF)
{
break;
}
cnt[ch]++;
}
#endif
for(int i = 1;i < 256;i++)
{
if(cnt[max] < cnt[i])
max = i;
}
fclose(fp);
printf("出现最多的字符是'%c',共出现了%d次\\n",max,cnt[max]);
return 0;
}
3.3.2.5fputs字符串的写入
原型:int fputs(const char *s, FILE *stream);
功能:
向流中写入s指向的字符串
参数:
s:要写入的字符串的首地址
stream:文件流指针
返回值:
成功返回非负数
失败返回EOF
写入hello world
#include <stdio.h>
int main(void)
{
FILE *fp = NULL;
char tmpbuff[]={"hello im dayang"};
fp = fopen("a.txt","w");
if(fp == NULL)
{
perror("file to fopen");
return -1;
}
fputs("hello im daynag\\n",fp);
fputs(tmpbuff,fp);
return 0;
}
3.3.2.6fgets读取一行字符串,遇到回车结束
原型:char *fgets(char *s, int size, FILE *stream);
功能:
从流中最多读size-1个字节数据放入s指向的空间中,遇到\\n读取截止
参数:
s:存放数据空间的首地址
size:最多存放元素的个数
stream:文件流指针
返回值:
成功返回存放数据空间的首地址
失败返回NULL
读到文件末尾返回NULL
读取文件并打印在终端:
#include <stdio.h>
int main(void)
{
FILE *fp = NULL;
char tmpbuff[1024] = {0};
char *pret = NULL;
fp = fopen("a.txt", "r");
if (NULL == fp)
{
perror("fail to fopen");
return -1;
}
while (1)
{
pret = fgets(tmpbuff, sizeof(tmpbuff), fp);//每次读取一行,遇到回车结束读取。
if (NULL == pret)
{
break;
}
printf("tmpbuff = %s", pret);
}
fclose(fp);
return 0;
}
用fgets和fputs实现文件拷贝:
#include <stdio.h>
#include <string.h>
void copy_file_content(char *pdstfile, char *psrcfile)
{
FILE *fp1 = NULL;
FILE *fp2 = NULL;
char ch[1024] = {0};
fp1 = fopen(pdstfile, "r");
if (NULL == fp1)
{
perror("fail to fopen");
return;
}
fp2 = fopen(psrcfile, "w");
if (NULL == fp2)
{
perror("fail to fopen");
return;
}
while (fgets(ch, sizeof(ch), fp1)!=NULL)
{
/*if (fgets(ch, sizeof(ch), fp1)==NULL)//不能写成while(1)嵌套if判断,这样会一次循环读两次,只会拷贝第二行。
{
break;
}*/
fputs(ch, fp2);
}
fclose(fp1);
fclose(fp2);
return;
}
int main(void)
{
char file1[256] = {0};
char file2[256] = {0};
printf("请输入源文件:\\n");
fgets(file1,sizeof(file1),stdin);
file1[strlen(file1)-1] = '\\0';
printf("请输入目的文件:\\n");
fgets(file2,sizeof(file2),stdin);
file2[strlen(file2)-1] = '\\0';
copy_file_content(file1,file2);
return 0;
}
封装函数,要求首次从终端输入数字到文件中,并计算输入数字的平均值,关闭程序再次运行时,会连带历史输入的所有数字计算其均值(具有记忆功能)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void in_put_num(char *atxt)
{
FILE *fp = NULL;
char ch[100]={0};
fp = fopen("a.txt","a");
if(fp == NULL)
{
perror("file to fopen");
return;
}
while(1)
{
fgets(ch, sizeof(ch), stdin);
ch[strlen(ch)-1]='\\0';
if(strcmp(ch, "-1") == 0)
{
break;
}
strcat(ch, "\\n");
fputs(ch,fp);
}
fclose(fp);
return;
}
float sum_of_numbers(char *atxt)
{
FILE *fp = NULL;
fp = fopen(atxt, "r");
char ch[100]= {0};
float sum = 0;
if (NULL == fp)
{
perror("fail to fopen");
return -1;
}
while (fgets(ch, sizeof(ch), fp) != NULL)
{
sum += atof(ch);
}
fclose(fp);
return sum;
}
int get_line(char *atxt)
{
int cnt = 1;
FILE *fp = NULL;
char ch = 0;
fp = fopen(atxt, "r");
if (NULL == fp)
{
perror("fail to fopen");
return -1;
}
while (1)
{
ch = fgetc(fp);
if (EOF == ch)
{
break;
}
if ('\\n' == ch)
{
cnt++;
}
}
fclose(fp);
return cnt;
}
int main(void)
{
float average = 0;
printf("请输入数字,输入-1结束并计算历史输入的均值\\n");
in_put_num("a.txt");
average = sum_of_numbers("a.txt")/(get_line("a.txt")-1);//行数会多统计一行
printf("average = %f\\n", average);
return 0;
}
跳出输入需要注意的事项:
#include <stdio.h>
#include <string.h>
int main(void)
{
char tmpbuff[1024] = {0};
while(1)
{
fgets(tmpbuff,sizeof(tmpbuff),stdin);
tmpbuff[strlen(tmpbuff)-1] = '\\0';
if(0 == strcmp(tmpbuff,"quit"))
{
break;
}
}
fputs(tmpbuff,stdout);
fputs("\\0",stdout);
return 0;
}
strcmp 是逐字符比较,直到遇到 \\0,但fgets读取结果为(读取的字符)\\n\\0,结果为quit\\n\\0
与截至条件不匹配。因此要tmpbuff[strlen(tmpbuff)-1] = '\\0';将\\n替换为\\0。
3.3.2.7fprintf写入到文件
原型:int fprintf(FILE *stream, const char *format, …);
功能:
将格式化的字符串打印在流中
参数:
stream:文件流指针
format:格式化的字符串
…:参数
返回值:
成功返回打印字符的个数
失败返回负数
功能用法与printf类似,只不过第一个参数为指向文件的指针。
#include <stdio.h>
int main(void)
{
FILE *fp = NULL;
int Num1 = 100;
int Num2 = 200;
fp = fopen("a.txt", "w");
if (NULL == fp)
{
perror("fopen failed\\n");
return -1;
}
fprintf(fp, "Num1 = %d, Num2 = %d\\n", Num1, Num2);
fclose(fp);
return 0;
}
3.3.2.8fscanf从文件中按指定格式读取数据
原型:int fscanf(FILE *stream, const char *format, …);
功能:
从流中接收格式化的字符串
参数:
stream:文件流指针
format:格式化字符串
…:参数
返回值:
成功返回匹配的输入控制符的个数
失败返回EOF
读到文件末尾返回EOF
从文件 a.txt 中读取两个整数值并打印到屏幕上:
#include <stdio.h>
int main(void)
{
FILE *fp = NULL;
int Num1 = 0;
int Num2 = 0;
fp = fopen("a.txt", "r");
if (NULL == fp)
{
perror("fail to fopen");
return -1;
}
fscanf(fp, "Num1 = %d, Num2 = %d", &Num1, &Num2);
printf("Num1 = %d, Num2 = %d\\n", Num1, Num2);
fclose(fp);
return 0;
}
3.3.2.9fwrite
原型:size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE
*stream);
功能:
向流中写入ptr指向的nmemb个对象,每个对象size个字节
参数:
ptr:指向数据空间的首地址
size:写入的每个对象的大小
nmemb:写入对象的个数
stream:文件流指针
返回值:
成功返回实际写入对象的个数
失败返回0
nret = fwrite(&s, sizeof(s), 1, fp); // 参数:数据地址 &s(数组可以不带&),每个元素大小 sizeof(s),写入数量 1,写入到fp
统计写入元素个数:
#include <stdio.h>
typedef struct student {
char name[32];
char sex;
int age;
int score;
}stu_t;
int main(void)
{
FILE *fp = NULL;
size_t nret = 0;
stu_t s = {"zhangsan", 'm', 18, 90};
stu_t s1 = {"lisi", 'f', 17, 80};
stu_t stu[3] = {
{"wanger", 'm', 16, 80},
{"zhaowu", 'f', 16, 70},
{"maliu", 'm', 15, 80},
};
fp = fopen("a.txt", "w");
if (NULL == fp)
{
perror("fail to fopen");
return -1;
}
nret = fwrite(&s, sizeof(s), 1, fp);
printf("nret = %ld\\n", nret);
nret = fwrite(&s1, sizeof(s1), 1, fp);
printf("nret = %ld\\n", nret);
nret = fwrite(stu, sizeof(stu_t), 3, fp);
printf("nret = %ld\\n", nret);
fclose(fp);
return 0;
}
3.3.2.10fread
原型:size_t fread(void *ptr, size_t size, size_t nmemb, FILE
*stream);
功能:
从流中读取nmemb个对象到ptr指向的空间中,每个对象size个字节
参数:
ptr:存放数据空间的首地址
size:读取对象的字节大小
memb:读取对象的个数
stream:文件流指针
返回值:
成功返回读到对象的个数
失败或者读到文件末尾返回0
nret = fread(stu, sizeof(stu_t), 10, fp);// 从文件中读取最多 10 个学生数据到数组 stu 中(不是数组的话要取地址)
//数据存储地址 stu,每个元素大小 sizeof(stu_t),最多读取数量 10,文件指针 fp
读取并打印:
#include <stdio.h>
typedef struct student
{
char name[32];
char sex;
int age;
int score;
}stu_t;
int main(void)
{
FILE *fp = NULL;
stu_t s;
stu_t stu[10];
size_t nret = 0;
int i = 0;
fp = fopen("a.txt", "r");
if (NULL == fp)
{
perror("fail to fopen");
return -1;
}
nret = fread(stu, sizeof(stu_t), 10, fp);//读一次一次读五个
printf("nret = %ld\\n", nret);
for (i = 0; i < nret; i++)
{
printf("姓名:%s\\n", stu[i].name);
printf("性别:%c\\n", stu[i].sex);
printf("年龄:%d\\n", stu[i].age);
printf("成绩:%d\\n", stu[i].score);
}
#if 0//读五次一次读一个
while (1)
{
nret = fread(&s, sizeof(s), 1, fp);
if (0 == nret)
{
break;
}
printf("nret = %ld\\n", nret);
printf("姓名:%s\\n", s.name);
printf("性别:%c\\n", s.sex);
printf("年龄:%d\\n", s.age);
printf("成绩:%d\\n", s.score);
}
#endif
fclose(fp);
return 0;
}
用fwrite和fread实现图片的拷贝:fread读取。fwrite写入。
#include <stdio.h>
int main(void)
{
FILE *fp1 = NULL;
FILE *fp2 = NULL;
char a[4096]={0};
size_t nret;
fp1 = fopen("p.jpg", "r");
if (NULL == fp1)
{
perror("fail to fopen1");
return -1;
}
fp2 = fopen ("a.jpg","w");
if (NULL == fp2)
{
perror("fail to fopen2");
return -1;
}
while (fread(a,sizeof(a) ,1, fp1))
{
fwrite(a,sizeof(a), 1, fp2);
}
fclose(fp1);
fclose(fp2);
return 0;
}//数据有损拷贝
不难看出,拷贝后文件不完全相同,出现了数据丢失。这是由于每次读取4096个字节,每次读取1次,会在最后一次读取时导致数据丢失,因为最后一次读取的时候数据不一定够4096。
(只会读取4096的整数倍)
我们试试另一种方法:
#include <stdio.h>
int main(void)
{
FILE *fp1 = NULL;
FILE *fp2 = NULL;
char a[4096]={0};
size_t nret;
fp1 = fopen("p.jpg", "r");
if (NULL == fp1)
{
perror("fail to fopen1");
return -1;
}
fp2 = fopen ("a.jpg","w");
if (NULL == fp2)
{
perror("fail to fopen2");
return -1;
}
while (nret = fread(a, 1, sizeof(a) , fp1))
{
fwrite(a, 1, nret, fp2);
}
fclose(fp1);
fclose(fp2);
return 0;
}//数据无损拷贝
而每次读取1个字节,实际读取多少字节,就返回写入多少字节,不会导致数据丢失。
4.流的定位
4.1偏移量的设置
4.1.1fseek偏移
原型:int fseek(FILE *stream, long offset, int whence);
功能:
设置流的偏移量的标识
参数:
stream:文件流指针
offset:偏移量
> 0 向后偏移
< 0 向前偏移
whence:标识
SEEK_SET 文件开头
SEEK_CUR 当前位置
SEEK_END 文件末尾
返回值:
成功返回0 失败返回-1
4.1.2ftell获取偏移量
原型:long ftell(FILE *stream);
功能:
获得流的偏移量
参数:
stream:文件流指针
返回值:
成功返回流的偏移量
偏移再写入并获取当前偏移量:
#include <stdio.h>
int main(void)
{
FILE *fp = NULL;
long len = 0;
fp = fopen("a.txt", "w");
if (NULL == fp)
{
perror("fail to fopen");
return -1;
}
fseek(fp, 10, SEEK_SET);//从开头向后偏移10个单位
fputc('a', fp);//写入a
len = ftell(fp);
printf("len = %ld\\n", len);//获取并打印偏移量
fseek(fp, -5, SEEK_CUR);//从当前位置向前偏移5个单位
fputc('b', fp);
len = ftell(fp);
printf("len = %ld\\n", len);
fseek(fp, 0, SEEK_END);//从文件末尾向前偏移5个单位
fputc('c', fp);
len = ftell(fp);
printf("len = %ld\\n", len);
rewind(fp);
// fseek(fp, 0, SEEK_SET);都可以做到偏移量初始化
fputc('d', fp);
len = ftell(fp);
printf("len = %ld\\n", len);
fclose(fp);
return 0;
}
4.1.3rewind重新定位到开头
原型:void rewind(FILE *stream);
功能:
将流重新定位到开头
统计文件字符数:
#include <stdio.h>
int main(void)
{
FILE *fp = NULL;
long len = 0;
fp = fopen("a.txt", "r");
if (NULL == fp)
{
perror("fail to fopen");
return -1;
}
fseek(fp, 0, SEEK_END);
fputc('d', fp);
len = ftell(fp);//偏移到末尾并统计偏移量也就是字符数。
printf("len = %ld\\n", len);
fclose(fp);
return 0;
}
输出bmp图片的宽度和高度:
#include <stdio.h>
int main(void)
{
FILE *fp = NULL;
int a[1] = {0};
size_t nret = 0;
fp = fopen("test.bmp", "r");
if (NULL == fp)
{
perror("fail to fopen");
return -1;
}
fseek(fp, 18, SEEK_SET);
nret = fread(a,1,4,fp);//每次读一个字节,读四次,读到a[0]里。
printf("宽度:%d",a[0]);
nret = fread(a,1,4,fp);//每次读一个字节,读四次,读到a[0]里。
printf("高度:%d",a[0]);
fclose(fp);
return 0;
}
#include <stdio.h>
int main(void)
{
FILE *fp = NULL;
int a[2] = {0};
size_t nret = 0;
fp = fopen("test.bmp", "r");
if (NULL == fp)
{
perror("fail to fopen");
return -1;
}
fseek(fp, 18, SEEK_SET);
nret = fread(a,4,2,fp);//每次读四个字节,读两次,读到a[0],a[1]里。
printf("宽度:%d",a[0]);
printf("高度:%d",a[1]);
fclose(fp);
return 0;
}
#include <stdio.h>
int main(void)
{
FILE *fp = NULL;
int width = 0;
int height = 0;
fp = fopen("test.bmp", "r");
if (NULL == fp)
{
perror("fail to fopen");
return -1;
}
fseek(fp, 18, SEEK_SET);
fread(&width, sizeof(width), 1, fp);
fread(&height, sizeof(height), 1, fp);
fclose(fp);
printf("宽度:%d, 高度:%d\\n", width, height);
return 0;
}
三种形式均可实现以下效果,无非是存储方式和变量参数不同。
5.标准IO的缓存
标准IO是一种有缓存的IO其效率高,实时性差。
5.1缓存类型
1)全缓存(4k):
刷新条件:缓存区满4k刷新,fflush函数强制刷新,fclose或者程序关闭刷新,与文件建立的缓存一般为全缓存。
2)行缓存(1k):
刷新条件: 缓存区满1k刷新,遇到\\n刷新,fflush函数强制刷新,fclose或者程序关闭刷新,与终端建立的缓存一般为行缓存(stdin、stdout均为行缓存)。
比如:
printf("hello world");
while(1)
{
}
这段代码不会打印在终端,其与终端建立联系,为行缓存,代码会一直卡在while循环中。
而这串代码:则会打印在终端,因为运行到\\n刷新了缓存,虽然代码依旧卡在while循环中,但仍会打印出字符串。
printf("hello world\\n");
while(1)
{
}
也可用fflash强制刷新缓存:
printf("hello world");
fflush(stdout); // 强制刷新输出缓冲区
while(1)
{
}
3)不缓存(0k):
刷新条件: 不缓存立即刷新,出错处理或者人机交互一般使用不缓存(stderr不缓存)。
评论前必须登录!
注册