当前位置: 首页 > news >正文

【Linux】基础IO(3)

1. 缓冲区

1.1 什么是缓冲区 

缓冲区是内存空间的⼀部分。也就是说,在内存空间中预留了⼀定的存储空间,这些存储空间用来缓冲输入或输出的数据,这部分预留的空间就叫做缓冲区。缓冲区根据其对应的是输入设备还是输出设备,分为输入缓冲区和输出缓冲区。

1.2 为什么要引入缓冲区机制

读写文件时,如果不会开辟对文件操作的缓冲区,直接通过系统调⽤对磁盘进行操作(读、写等),那么每次对文件进行⼀次读写操作时,都需要使⽤读写系统调用来处理此操作,即需要执行⼀次系统调⽤,执⾏⼀次系统调⽤将涉及到CPU状态的切换,即从用户空间切换到内核空间,实现进程上下文的切换,这将损耗⼀定的CPU时间,频繁的磁盘访问对程序的执⾏效率造成很⼤的影响。
为了减少使⽤系统调⽤的次数,提⾼效率,我们就可以采⽤缓冲机制。比如我们从磁盘⾥取信息,可以在磁盘⽂件进行操作时,可以⼀次从⽂件中读出⼤量的数据到缓冲区中,以后对这部分的访问就不需要再使⽤系统调⽤了,等缓冲区的数据取完后再去磁盘中读取,这样就可以减少磁盘的读写次数,再加上计算机对缓冲区的操作⼤ 快于对磁盘的操作,故应⽤缓冲区可⼤ 提⾼计算机的运⾏速度。
又⽐如,我们使⽤打印机打印⽂档,由于打印机的打印速度相对较慢,我们先把⽂档输出到打印机相应的缓冲区,打印机再自行逐步打印,这时我们的CPU可以处理别的事情。可以看出,缓冲区就是⼀块内存区,它⽤在输⼊输出设备和CPU之间,⽤来缓存数据。它使得低速的输⼊输出设备和高速的CPU能够协调⼯作,避免低速的输⼊输出设备占⽤CPU,解放出CPU,使其能够⾼工作效率。

1.3 缓冲类型

标准I/O提供了3种类型的缓冲区。
全缓冲区:这种缓冲方式要求填满整个缓冲区后才进⾏I/O系统调用操作。对于磁盘文件的操作通常使用全缓冲的方式访问。

行缓冲区:是标准 I/O 库针对终端相关流(如标准输入、标准输出)采用的缓冲方式。其工作机制为:当输入或输出过程中遇到换行符\n时,标准 I/O 库会执行系统调用,将缓冲区数据实际传输;同时,由于行缓冲区有固定默认大小(1024 字节),若数据填满缓冲区,即使未遇到换行符,也会触发系统调用完成数据传输。

⽆缓冲区:⽆缓冲区是指标准I/O库不对字符进行缓存,直接调用系统调用。标准出错流stderr通常是不带缓冲区的,这使得出错信息能够尽快地显示出来。
除了上述列举的默认刷新⽅式,下列特殊情况也会引发缓冲区的刷新:
1. 缓冲区满时;
2. 执⾏flush语句;
3. 进程结束

例子:

#include <cstdio>
#include <iostream>
#include <cstring>
#include <unistd.h>int main()
{// 库函数printf("hello printf\n");fprintf(stdout, "hello fprintf\n");const char *s = "hello fwrite\n";fwrite(s, strlen(s), 1, stdout);// 系统调用const char *ss = "hello write\n";write(1, ss, strlen(ss));//???fork();return 0;
}

场景 1:直接终端运行(./newcode

输出:

hello printf
hello fprintf
hello fwrite
hello write
  • printf/fprintf/fwrite:因输出到终端,stdout 是行缓冲,且内容带 \n,所以立即刷新缓冲区,直接输出。
  • write:系统调用,无缓冲,直接输出。
  • fork:此时缓冲区已被 “行缓冲 + \n” 刷空,子进程复制后无残留数据,退出时不额外输出。
场景 2:重定向到文件(./newcode > log.txt

输出(cat log.txt 结果):

hello write
hello printf
hello fprintf
hello fwrite
hello printf
hello fprintf
hello fwrite

原因:

  1. 重定向后缓冲变化stdout 重定向到文件,变为全缓冲(需进程退出才刷新)。
  2. fork 前的输出操作
    • printf/fprintf/fwrite:内容进入用户空间全缓冲(未刷新,因为缓冲区没满、没 fflush);
    • write:系统调用,无缓冲,直接写入文件,所以最先输出。
  3. fork 与子进程复制
    • 父进程执行 fork,子进程复制父进程的全缓冲缓冲区(此时 printf/fprintf/fwrite 的内容还在缓冲区里)。
  4. 进程退出刷新
    • 父进程退出时,刷新自己的缓冲区 → 输出 hello printf/hello fprintf/hello fwrite
    • 子进程退出时,也会刷新复制来的缓冲区 → 再次输出 hello printf/hello fprintf/hello fwrite
综上: printf fwrite 库函数会自带缓冲区,而 write 系统调用没有带缓冲区。另外,我们这
⾥所说的缓冲区,都是用户级缓冲区。其实为了提升整机性能,OS也会提供相关内核级缓冲区。
那这个缓冲区谁提供呢? printf fwrite 是库函数, write 是系统调⽤,库函数在系统调用
的“上层”, 是对系统调⽤的“封装”,但是 write 没有缓冲区,而 printf fwrite 有,⾜以
说明,该缓冲区是⼆次加上的,⼜因为是C,所以由C标准库提供
http://www.dtcms.com/a/405856.html

相关文章:

  • 【Redis学习】Redis中常见的全局命令、数据结构和内部编码
  • AI行业应用深度解析:从理论到实践
  • AI 伦理审查破局:从制度设计到实践落地的 2025 探索
  • RocketMQ面试问题与详细回答
  • 多传感器数据融合到base_link坐标系下
  • 阿里新开源Qwen3-Omni技术解析
  • Flink 流式分析事件时间、Watermark 与窗口
  • 解析前端框架 Axios 的设计理念与源码
  • 使用IOT-Tree消息流InfluxDB模块节点实现标签数据的时序数据库存储
  • 【深入理解JVM】垃圾回收相关概念与相关算法
  • 文档抽取技术:金融保险行业数字化转型的核心驱动力之一
  • 神秘魔法?耐达讯自动化Modbus TCP 转 Profibus 如何为光伏逆变器编织通信“天网”
  • 做庭院的网站佛山网站专业制作
  • wordpress开启多站点营销云官网
  • 企业AI 智能体(AI_Agent)落地开源方案:Dify、n8n、RAGFlow、FastGPT、AutoGen和OAP深度梳理与对比分析
  • Day51 时钟系统与定时器(EPIT/GPT)
  • Django 搭配数据库开发智慧园区系统全攻略
  • 前端基础知识---10 Node.js(三)
  • article.3345645398
  • 国内如何使用GPT-5-Codex
  • Xcode 26 could not locate developer disk image for this device 无法定位开发者磁盘镜像
  • 用Python打造离线语音控制浏览器:基于VOSK的实用案例
  • 【ARDUINO】在arduino ide中下载安装开发包失败了,如何手动安装开发包
  • 上架 App 全流程解析,iOS 应用上架步骤、App Store 审核流程、ipa 文件上传与测试分发经验
  • 网站审核要多久老铁外链
  • 网站建设公司的服务公司湖南做网站 在线磐石网络
  • Linux的写作日记:Linux基础开发工具(二):vim编辑器
  • nginx缓存、跨域 CORS与防盗链设置(2)
  • 多级缓存架构:性能与数据一致性的平衡处理(原理及优势详解+项目实战)
  • 今天我们开始学习nginx缓存功能,CORS以及nginx防盗链