标准IO介绍 文件IO介绍及缓冲区概念
IO概述:
IO(input/output)是计算机系统中数据在不同实体间传输交互的抽象过程,涵盖程序与外部设备(如文件、硬件、网络)的数据读写行为。本质上,它是程序与外部环境建立“数据通道”的核心机制,支撑着程序获取输入、输出结果的基本逻辑,是软件与硬件、本地与远程交互的底层依托;
IO作用:
IO是程序与外部环境交互的基础桥梁。一方面,它为程序提供“输入”能力,支撑程序从文件、硬件、网络获取运行所需的数据;另一方面,通过“输出”功能,程序可将计算结果持久化存储,可视化展示或远程传输;
IO种类:
可从实现层级和应用场景两个维度分类
实现层级分类:
系统调用IO:也称为文件IO,直接对接操作系统内核的最底层接口;逻辑极简、性能接近硬件,但是需要手动处理缓冲区、错误码等细节;
库函数IO:也称之为标准IO,基于系统调用封装的高层接口;自动管理缓冲区、跨平台兼容、简化开发,使用户态程序的常用选择;
应用场景分类:
文件IO:针对磁盘文件的读写,可通过“系统调用”或”库函数“实现
设备IO:与硬件设备交互。操作系统通过“设备抽象”将设备转换为文件系统中的特殊文件,使程序能用统一的文件操作接口访问所有硬件
网络IO:实现网络数据收发,依赖系统调用或者使更高层的框架。
定义:
标准I/O是C库提供的输入输出函数集合,由ANSI C标准统一规范,为跨平台IO操作奠定基础
跨平台性:在UNIX系统、windows系统、Linux等多系统操作均实现标准I/O库,让代码跨平台开发更顺畅
高效实现原理:通过缓冲机制(内存临时存储数据),减少直接系统调用次数,降低硬件交互开销,提升IO效率
易用性设计:基于系统底层调用封装,屏蔽复杂硬件操作,开发者无需关注设备细节,简单调用函数即可完成IO;
流
定义:所有I/O操作抽象为字节的“移入/移出”程序的过程,这种字节流动形态,称为流。
分类:
- 文件流:按字符编码(如ASCII、UTF-8)处理,注重文本语义;
- 二进制流:直接操作原始字节,保留数据原始形态(如图片、可执行文件);
默认打开的流:
- stdin:标准输入流(如键盘输入)
- stdout:标准输出流(如屏幕打印)
- stderr:标准错误流(专用于输出错误信息)
FILE对象
定义:
FILE对象是一个结构体,用于存储文件或流相关的所有状态信息
FILE对象与流对应关系:
每个流在内存中由一个FILE对象表示,通过FILE*指针访问;
标准流的特殊FILE对象:
- stdin:是标准输入流对应的FILE对象指针,通常关联到键盘输入
- stdout:是标准输出流对应的FILE对象指针,通常关联到控制台输出;
- sterr:是标准错误流对应的FILE对象指针。通常关联到控制台,用于输出错误信息;
由于FILE对象通常较大且内部结构复杂,标准I/O函数不直接操作FILE对象本身,而是通过FILE指针来间接访问。FILE指针是指向FILE对象的内存地址,所有文件操作都基于这个指针进行;
FILE指针创建与销毁:通过fopen()进行创建FILE指针,通过fclose()进行销毁FILE指针;
FILE指针操作:所有标准I/O函数都以FILE指针作为参数,常见操作包括读写、定位、错误检查
FILE对象与底层系统调用的关系:FILE对象是标准库层面的抽象,而LINUX内核通过文件描述符(如0、1、2对应标准输入/输出/错误)管理文件。FILE对象内部维护了一个文件描述符,将标准I/O函数映射到底层系统调用,并提供缓冲区优化。
数据流动流程图
标准IO的缓冲区
定义:标准I/O中的缓冲区是C语言标准库为优化文件读写效率设计的内存机制,本质上是一段由FILE结构体管理的内存空间
作用:通过临时存储数据、批量处理,可以减少硬件IO(如磁盘、终端)的交互次数,提升程序效率;
缓冲策略:标准I/O中设计了行缓冲、全缓冲、无缓冲三种策略,来适配不同的场景,也支持手动修改;
行缓冲:默认用于终端设备(如stdout、stdin),Linux系统中行缓冲的大小为1024kb;
全缓冲:默认用于文件,LInux系统中全缓冲大小通常为4096kb;
无缓冲:不使用临时内存暂存,数据直接写入硬件;无缓冲区的大小为0
行缓冲刷新时机
- 遇到换行符“\n”会刷新缓冲区;
- 程序正常结束会刷新缓冲区;
- 当文件关闭时会刷新缓冲区;
- 在输入和输出发生切换时会刷新缓冲区;
- 缓冲区写满(未到换行符)会刷新缓冲区;
- 主动调用fflush函数会强制刷新缓冲区;
行缓冲和全缓冲的区别是:全缓冲不会遇到换行符刷新
fflush函数
文件IO介绍
定义:文件IO是在POSIX(可移植操作系统接口)中定义的一组输入输出的函数,涉及操作系统和应用程序之间的交互,用于读取和写入存储在永久性存储介质(如硬盘、SSD、USB闪存盘等)的数据;
跨平台性:不同操作系统(如UNIX、Windows、Linux)的文件IO机制存在差异,接口、调用方式和底层实现逻辑各有特点
高效实现原理:
- 直接交互硬件/文件系统:绕过高级缓冲,直接发起系统调用访问磁盘等设备,数据传输路径段,适合对实时性、精准控制要求高的场景;
- 无用户态缓冲:不依赖用户态缓冲机制,每次读写更贴近硬件真实操作,但频繁调用会增加系统开销,需开发者按需优化;
易用性设计:
贴近底层逻辑:需开发者熟悉操作系统API、文件权限、设备特性等,直接处理缓冲区管理、错误码解析,对开发经验要求高;
灵活但复杂:可精准控制文件打开模式、数据传输细节,却也因修手动处理资源释放、并发冲突等问题,增加开发复杂度;
特点:
- 没有缓冲机制,每次调用都会引起系统调用;
- 围绕文件描述符进行操作,相当于标准IO中的流(FILE*),文件描述符是正整数;
- 默认打开三个描述符:标准输入(o) 标准输出(1) 标准错误(2)
- 除目录文件,其他类型文件都可以操作;
- 可移植性相对较弱
与标准IO对比
文件描述符
定义:文件描述符是操作系统内核为每个打开的文件/设备分配的唯一整数标识符,用于标识和跟踪进程与文件的交互,在Linux/Unix中,它是底层文件IO操作的核心参数;
本质:
- 它是指向内核中维护的文件表(File Table),该表中记录了文件的状态,位置指针等信息;
- 每个进程都有自己独立的文件描述符表,通常是从0开始的编号,相互不干扰;Linux系统中一个正在执行的陈鼓型中文件描述符的范围是【0-1023】,可通过ulimit调整,一般使用默认值;
作用:
- 连接用户进程与内核资源:通过文件描述符,进程可以请求内核进行文件续写、设备操作等,无需关心底层实现细节;
- 资源管理:操作系统通过文件描述符跟踪那些文件被那些进程打开,并在进程关闭文件活退出时自动回收资源
特点:
- 唯一性:同一个进程内,每个文件描述符对应唯一的打开文件;
- 非负整数:通常是小整数(如0、1、2),但可动态分配(如open()返回的新描述符);
- 跨函数传递:可在不同系统调用间传递,代表对同一文件的持续操作;
常见文件描述符编号:
