关于标准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. Rainbond结合NeuVector实践容器安全管理

    前言 Rainbond 是一个云原生应用管理平台,使用简单,不需要懂容器.Kubernetes和底层复杂技术,支持管理多个Kubernetes集群,和管理企业应用全生命周期.但是随着云原生时代的一点点 ...

  2. Ubuntu中安装redis

    第一种方式在线安装首要前提安装c语言编译环境,命令如下:$sudo apt-get install gcc 安装完成后可以输入$gcc --version查看版本 1.获取源码:$wget https ...

  3. Redis进阶知识一览

    Redis的持久化机制 RDB: Redis DataBase 什么是RDB RDB∶每隔一段时间,把内存中的数据写入磁盘的临时文件,作为快照,恢复的时候把快照文件读进内存.如果宕机重启,那么内存里的 ...

  4. 无线:WPA

    WPA全名为Wi-Fi Protected Access,有WPA和WPA2两个标准,是一种保护无线电脑网络(Wi-Fi)安全的系统,它是应研究者在前一代的系统有线等效加密(WEP)中找到的几个严重的 ...

  5. 824. Goat Latin - LeetCode

    Questioin 824. Goat Latin Solution 题目大意:根据要求翻译句子 思路:转换成单词数组,遍历数组,根据要求转换单词 Java实现: 用Java8的流实现,效率太低 pu ...

  6. Nginx分片限流

    一.全局限流 在http节点中添加 # 创建限流规则 limit_req_zone $binary_remote_addr zone=addr:10m rate=1r/s;# 客户端进行限流 # li ...

  7. 论文解读(GraphDA)《Data Augmentation for Deep Graph Learning: A Survey》

    论文信息 论文标题:Data Augmentation for Deep Graph Learning: A Survey论文作者:Kaize Ding, Zhe Xu, Hanghang Tong, ...

  8. 管理订单状态,该上状态机吗?轻量级状态机COLA StateMachine保姆级入门教程

    前言 在平常的后端项目开发中,状态机模式的使用其实没有大家想象中那么常见,笔者之前由于不在电商领域工作,很少在业务代码中用状态机来管理各种状态,一般都是手动get/set状态值.去年笔者进入了电商领域 ...

  9. 【原创】项目三Raven-2

    实战流程 1,C段扫描,并发现目标ip是192.168.186.141 nmap -sP 192.168.186.0/24 扫描目标主机全端口 nmap -p- 192.168.186.141 访问8 ...

  10. 以字节跳动内部 Data Catalog 架构升级为例聊业务系统的性能优化

    背景 字节跳动 Data Catalog 产品早期,是基于 LinkedIn Wherehows 进行二次改造,产品早期只支持 Hive 一种数据源.后续为了支持业务发展,做了很多修修补补的工作,系统 ...