关于标准IO缓冲区的问题

按照标准IO缓冲区可以分为三类:

不缓存类型:

  • 一旦有数据,直接将数据写入到文件

行缓冲类型:

  • 同全缓冲类型
  • 遇到\n时,将数据写入文件

全缓冲类型:

  • 当程序结束,将数据冲洗到文件
  • 当遇见fflush(),将数据冲洗到文件
  • 当文件关闭时,将数据冲洗到文件
  • 当遇到读取操作,将数据冲洗到文件
  • 当改变缓冲区的类型时,将数据冲洗到文件
  • 当缓冲区满了,将数据冲洗到文件

对于标准输出而言,默认是行缓冲

对于标准出错而言,默认是不缓存

对于普通文件而言,默认是全缓冲

#include <stdio.h>
#include <unistd.h>
int main(int argc, char const *argv[])
{
// w+ 以读写的方式打开文件,若文件存在则清空文件数据,若文件不存在,则创建文件
FILE *fp = fopen("_a.txt", "w+"); // 将数据写入文件
fputs("123", fp); //暂停程序不让,不让程序正常结束,观察a.txt文件内容
pause();
return 0;
}

我们能看到文件被创建,但是文件内没有内容。

我们来分析一下,我们此时是以普通文件操作,此时是默认的全缓冲,且调用了pause()函数,程序没有正常的结束,所以能猜想到此刻的内容是在缓冲区里,没有被冲洗至文件中。如果我们把pause()进行注释,在执行该程序,我们能看到我们要写入的数据出现在_a.txt文件中。这也是全缓冲类型的第一次情况,当程序结束,将数据读取到文件。

接下来我们来看一下这段代码:

#include <stdio.h>
#include <unistd.h>
int main(int argc, char const *argv[])
{
FILE *fp = fopen("_a.txt", "w+"); fputs("123", fp);
fflush(fp); pause();
return 0;
}

印证第二种情况我们直接用冲洗函数fflush(),能看到数据成功读取到文件中。

第三种情况,在fput函数和pause函数中间,调用fclose(),关闭文件。

#include <stdio.h>
#include <unistd.h>
int main(int argc, char const *argv[])
{
FILE *fp = fopen("_a.txt", "w+"); fputs("123", fp);
fclose(fp); pause();
return 0;
}

第四种情况,当遇到读取操作,将数据冲洗到文件。

#include <stdio.h>
#include <unistd.h>
int main(int argc, char const *argv[])
{
FILE *fp = fopen("_a.txt", "w+"); fputs("123", fp);
fgetc(fp); pause();
return 0;
}

接下来我们看一下通过setvbuf()改变缓冲区的类型,进而对缓冲区的冲洗操作。

简单的介绍一下:setvbuf函数



这图片是我在man手册截图下来的。

int setvbuf(FILE *stream, char *buffer, int mode, size_t size)

stream -- 这是指向 FILE 对象的指针,该 FILE 对象标识了一个打开的流。

buffer -- 这是分配给用户的缓冲。如果设置为 NULL,该函数会自动分配一个指定大小的缓冲。

mode -- 这指定了文件缓冲的模式。

_IOFBF 全缓冲
_IOLBF 行缓冲
_IONBF 无缓冲

size --这是缓冲的大小,以字节为单位。

返回值:如果成功,则该函数返回 0,否则返回非零值。

#include <stdio.h>
#include <unistd.h>
int main(int argc, char const *argv[])
{
FILE *fp = fopen("_a.txt", "w+");
// setvbuf(fp, NULL, _IONBF, 0);
fputs("123", fp); setvbuf(fp, NULL, _IONBF, 0); pause();
return 0;
}

我们这里的语句是setvbuf(fp, NULL, _IONBF, 0),把普通文件默认的全缓冲,转换成无缓冲,数据在文件中有所显示,所以符合我们的第五条理论。这是为了突出我们的第五条理论,因此将该语句放置在fput语句的后面,当然如果我们在setvbuf(fp, NULL, _IONBF, 0)后面写上相同的fputs语句或者将setvbuf(fp, NULL, _IONBF, 0),放置至fopen语句后面也是会相同的效果。不过第二种情况的理解不同,此刻能成功读取数据不是因为缓冲区类型的转换,而是因为它此刻已经被定义为无缓冲,所以数据直接读取至文件中。

我们这里不妨试一试自己定义一个100字节的buf缓冲区,且在读取数据之前就将缓冲区类型转换至行缓存,观察是否能通过\n来将数据读取至文件当中去。(冲洗行缓冲)。


#include <stdio.h>
#include <unistd.h>
int main(int argc, char const *argv[])
{
FILE *fp = fopen("_a.txt", "w+");
char buf[1024]; setvbuf(fp, buf, _IOLBF, 1024); //这里是行缓冲,如果要将数据冲洗至普通文件,注意要加\n
fputs("123\n", fp); pause();
return 0;
}

总之,滞留在缓冲区中的数据有时被称为脏数据(dirty data),脏数据的存在代表程序操作的结果与文件真实状态不一致,若未正常冲洗这些脏数据就退出程序则有可能会造成数据丢失,我们在使用IO对数据操作时要注意对缓冲区的问题

关于标准IO缓冲区的问题的更多相关文章

  1. linux标准IO缓冲(apue)

    为什么需要标准IO缓冲? LINUX用缓冲的地方遍地可见,不管是硬件.内核还是应用程序,内核里有页高速缓冲,内存高速缓冲,硬件更不用说的L1,L2 cache,应用程序更是多的数不清,基本写的好的软件 ...

  2. linux标准io的copy

    ---恢复内容开始--- 1.linux标准io的copy #include<stdio.h> int main(int argc,char **argv) { if(argc<3) ...

  3. 第十三篇:带缓冲的IO( 标准IO库 )

    前言 在之前,学习了 read write 这样的不带缓冲IO函数. 而本文将讲解标准IO库中,带缓冲的IO函数. 为什么要有带缓冲IO函数 标准库提供的带缓冲IO函数是为了减少 read 和 wri ...

  4. C5 标准IO库:APUE 笔记

    C5 :标准IO库 在第三章中,所有IO函数都是围绕文件描述符展开,文件描述符用于后续IO操作.由于文件描述符相关的操作是不带缓冲的IO,需要操作者本人指定缓冲区分配.IO长度等,对设备环境要求一定的 ...

  5. 为什么需要标准IO缓冲?

    (转)标准I/O缓冲:全缓冲.行缓冲.无缓冲 标准I/O库提供缓冲的目的是尽可能地减少使用read和write调用的次数.它也对每个I/O流自动地进行缓冲管理,从而避免了应用程序需要考虑这一点所带来的 ...

  6. 带标准IO带缓存区和非标准IO 遇到fork是的情况分析

    废话不多说 直接代码 #include<stdio.h> #include<sys/types.h> #include<unistd.h> #include< ...

  7. 带缓冲的IO( 标准IO库 )

    前言 在之前,学习了 read write 这样的不带缓冲IO函数.而本文将讲解标准IO库中,带缓冲的IO函数. 为什么要有带缓冲IO函数 标准库提供的带缓冲IO函数是为了减少 read 和 writ ...

  8. 深究标准IO的缓存

    前言 在最近看了APUE的标准IO部分之后感觉对标准IO的缓存太模糊,没有搞明白,APUE中关于缓存的部分一笔带过,没有深究缓存的实现原理,这样一本被吹上天的书为什么不讲透彻呢?今天早上爬起来赶紧找了 ...

  9. 【linux草鞋应用编程系列】_1_ 开篇_系统调用IO接口与标准IO接口

    最近学习linux系统下的应用编程,参考书籍是那本称为神书的<Unix环境高级编程>,个人感觉神书不是写给草鞋看的,而是 写给大神看的,如果没有一定的基础那么看这本书可能会感到有些头重脚轻 ...

随机推荐

  1. 实战派 | Java项目中玩转Redis6.0客户端缓存!

    原创:微信公众号 码农参上,欢迎分享,转载请保留出处. 哈喽大家好啊,我是Hydra. 在前面的文章中,我们介绍了Redis6.0中的新特性客户端缓存client-side caching,通过tel ...

  2. spring boot redis 写入异常

    redis 的 key value 使用 json 序列化.反序列化时,写入的 bean 不能是 final 类型的类,否则无法解析

  3. Hadoop常见shell命令

    Hadoop中常见的shell命令 1.如何将Linux本地的数据上传到HDFS中? hadoop fs -put 本地的文件 HDFS中的目录hdfs dfs -put 本地的文件 HDFS中的目录 ...

  4. C#获取PLC信息 (KepServer)

    首先注册DLL 我这里把此DLL放到我自己的网站上了,供大家下载 https://blog.nwctwang.top/OPCDAAuto.dll 把此dll复制到C:\Windows\SysWOW64 ...

  5. 中国程序员容易发错音的单词「GitHub 热点速览 v.22.23」

    中国程序员容易发错音的单词,像极了学生时代的纠错本,收录着偶尔会忘记的单词.不过,它似乎更新频率跟不上我们的进步速度,至少一半以上的单词读起来是没有压力的.同样没有压力的还有让应用程序动起来的 aut ...

  6. python基础学习8

    python基础学习8 内容概要 字典的内置方法 元组的内置方法 集合的内置方法 垃圾回收机制 内容详情 字典的内置方法 一.类型转换 res = dict(name='jason', pwd=123 ...

  7. 互联网公司目标管理OKR和绩效考核的误区

    最近看了一篇关于「谷歌放弃OKR,转向全新的GRAD系统」的文章,我转到了研发效能DevOps的微信群里,结果引起了大家热烈的讨论,正好我们也在使用 OKR,所以也来谈谈我的理解以及我们应用起来的实际 ...

  8. .net core 抛异常对性能影响的求证之路

    一.前言 在.net 社区中曾经听到过很多关于大量抛异常会影响性能这样的结论,心中一直就存在各种疑问.项目中使用自定义异常来处理业务很爽,但是又担心大量抛业务异常存在性能问题. 查阅了各种文档,微软官 ...

  9. BUUCTF-[BJDCTF2020]你猜我是个啥

    [BJDCTF2020]你猜我是个啥 下载压缩包提示打不开,16进制直接拉最下方可以查看到flag flag{i_am_fl@g}

  10. Windows-安装OpenVINO

    安装指导书链接: https://docs.openvinotoolkit.org/latest/openvino_docs_install_guides_installing_openvino_wi ...