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

Linux:标准IO

标准IO概念

Linux操作系统分层结构

结构

应用层 应用程序: app app

C库函数 (标准IO)

内核层 系统调用(文件IO)

内核

驱动

硬件层 硬件

标准IO

系统调用能提供给内核层与用户层打交道的接口

标准IO

IO概述:IP是计算机系统中数据在不同实体间传输交互的抽象过程,涵盖程序与外部设备(如文件、硬件、网络)的数据书写行为。本质上,它是程序与外部环境建立“数据通道”的核心机制,支撑程序获取输入、输出结果的基本逻辑,是软件与硬件、本地与远程交换的底层依托;

IO作用:是程序与外部环境交互的基础桥梁

标准IO介绍

定义:标准I/O是C库提供的输入输出函数集合,由ANSI C 标准统一规范,为跨平台IO操作奠定基础;

跨平台性:在UNIX系统、Windows系统、Linux等多系统操作均实现标准I/O库

高效实现原理:

通过缓冲机制(内存临时存储数据);减少系统调用次数,

降低硬件交互开销(间接操作硬件),提示IO效率

易用性设计:

基于系统底层调用封装,屏蔽复杂硬件操作,开发者无线关注设备细节,简单调用函数即可完成

系统调用与库函数的区别

对比维度系统调用(文件IO)库函数(标准IO)
层级定位(定义)操作系统提供的底层接口(如open)基于系统调用、纯用户逻辑封装的高层工具(如C标准库fopen)
调用对象文件描述符(int fd)文件流指针(FILE *fd)
运行空间运行于内核空间,需切换CPU特权级(用户态->内核态)运行于用户空间,无需特权级切换
功能本质直接操作硬件/内核资源(如读写磁盘、创建进程)

调用封装函数

①封装系统调用实现复制功能(如printf调用write)

②纯用户逻辑(如strlen计算字符串长度)

缓冲区无缓冲,直接写入内核有缓冲,默认缓存区,有三个:全缓存、行缓存、与无缓存
性能开销由于‘用户态<->内核态’切换,开销较大

①若封装系统调用,开销略低(减少切换次数)

②纯用户态函数开销极小

移植性依赖操作系统内核,移植性差(如Linux与Windows系统调用不同)跨平台(如C标准库),移植性好(同一函数适配多系统)

流(stream)

定义:所有I/O操作抽象为字节的“移入/移出”程序的过程,这种字节流动形态,称为流。

分类:

文件流:按字符编码(如ASCII、UTF-8)处理,注重文本语义,适用于文本文件;

二进制流:直接操作原始字节,保留数据原始形态(如图片、可执行文件)

FILE对象

定义:FILE对象(文件管家)是一个结构体(结构体中的成员是管家记录本和临时仓库),用于存储文件或流相关的所有状态信息(如文件描述符、缓冲区大小、缓冲区当前位置、文件模式标志等等);(FILE对象是FILE结构体的别名)

FILE对象与流对应关系:

每一个流在内存中由一个FILE对象表示,通过FILE指针访问

标准流的特殊FILE对象:

stdin:是标准输入流对应的FILE对象指针,通常关联到键盘输入

stdout:是标准输出流对应的指针,通常关联到控制台输出;

stderr:是标准错误流对应的指针,通常关联到控制台,用于输出错误信息

由于FILE对象通常较大且内部结构复杂,标准I/O函数不直接操作FILE对象本身,

而是通过FILE指针(FILE*)来间接访问。FILE指针是指向FILE对象的内存地址,所有文件操作(如打开、读写、关闭)都基于这个指针进行;

FILE指针创建与销毁:通过fopen()进行创建FILE指针,通过fclose()进行销毁FILE指针;

标准IO函数(一)

man手册使用方式

文件打开函数

fopen有两个参数

//一个参数是要打开的文件指针,即数据流,另一个是模式类型,用""引起来,它是字符串类型;

函数原型 FILE *fopen(const char *pathname,char *node);

fopen("test.c","w")//文件以只写的方式打开;如果文件不存在则会创建文件

//如果文件存在则会清空文件

fopen("test.c","r") //以只读的方式打开文件,如果文件不存在则会进行报错,文件存在就打印成功

不存在的情况包括路径不对或文件名错误的问题

fopen("test.c","a") //以追加的方式打开文件,如果文件不存在,创建文件;

//如果文件存在不会清空文件的原有内容

//联合fprintf、fput、fwrite写入

1>fprintf打印的是写给人看的文本;它是用来追加文本的,称为格式化文本输出函数

f2>write是写入的二进制文件,写在.c的代码中时乱码,

写文件必须是文本写入模式与格式化输出函数结合使用,才能追加

fwrite只能写入二进制文件,写入模式为-ab,写入data.bin,而不是test.c或text.h

它的格式与fprintf都不同,格式如下:

int numbers[] = {10, 20, 30};

//参数含义:(数据源, 单个元素大小, 元素个数, 文件指针)

fwrite(numbers, sizeof(int), 3, fp);

3>fputs写入的是纯文本,

内核中的错误码问题

错误码转换为错误信息-strerror函数(也称转换函数)

错误码是1,2...等数字,各代表一种错误,如何把错误码转换成错误信息(即字符串的文本信息);用到了strerror函数,这个函数定义在string.h这个头文件里,直接引用

错误信息打印函数-perror函数(直接显示错误,不转换)

perror函数在头文件stdio.h

perror("文件打开失败");//用这个,而不用没有提示的

运行结果如图

//我们在使用perror函数的时候最好给一个用户的错误信息

perror("");//没有提示的信息如下

字符串写函数

fputs函数

它的函数原型是int fputc(int c,FLLE *stream)

//第一个参数是要写入的字符,第二个参数是这个文件指针(内容);

返回值:成功是返回写入的字符的ascii码值

失败是返回EOF,是int类型,定义在宏

字符串读函数

fgetc函数:

fgetc函数原型是:int fgetc(FILE *stream)

//参数是一个文件指针,即stream,stream指向的是这个文件的内容,也称为数据流

main函数的(int argc ,const char argv[])

//第一个参数argc是代表字符串的个数,第二个参数argv代表字符串数组,输出的是这个数组下标的字符串名字

缓冲区

标准IO缓存

作用:通过临时存储数据、批量处理,可以减少硬件IO(像磁盘终端)的交互次数,提升程序效率

缓冲区,只有我们使用缓冲区时,系统才为缓冲区分配空间,分配实际的大小,如果不使用就是0。

缓冲区分为:行缓存(1024个字节)s用于终端设备如stdout/stdin;

全缓存(4096)用于文件如.txt

无缓存:(0字节)

缓存区刷新机制

即触发条件:

行缓存区:6点

1>当遇到换行符的时候刷新缓存区

2>当程序正常结束时刷新缓存区//记关闭文件,程序结束就是默认关闭了文件

3>当文件关闭时(文件指针流关闭)时刷新缓冲区(fclose)

4>当输入与输出进行切换时刷新缓冲区

5>当缓冲区写满的时候会刷新缓冲区(不是遇到换行符的情况)

6>主动调用fflush函数时会刷新缓冲区

全缓存区:5点,与行缓冲相似

全缓存区与行缓冲区的区别是行缓冲区多了一个遇到换行符会刷新缓冲区,而全缓冲区不会。

为什么char buf[BUFSIZ];不需要初始化?

因为程序是先写入后读先用了fputs再用的fgets;

fputs把垃圾值覆盖掉了,放的是新值

fgets 会做两件事: 把文件内容放进 buf 自动在最后加 \0→ 覆盖了所有垃圾→ 完全安全

c

运行

char buf[BUFSIZ];

定义数组但不初始化 →里面是随机垃圾值(随机内存)

❌ 错误:先读

c

运行

printf("%s", buf);

printf遇到%s会一直找字符串结束符\0但数组里全是垃圾,找不到\0→ 结果:乱码 + 越界 + 崩溃

✅ 正确:先写

c

运行

fgets(buf, sizeof(buf), fp);

fgets会做两件事:

  1. 把文件内容放进 buf
  2. 自动在最后加\0→ 覆盖了所有垃圾→ 完全安全

4. 最关键的规则(背下来)

谁先使用,谁负责初始化!

  • 先读(使用)→ 必须初始化
  • 先写(覆盖)→ 不需要初始化

你现在的代码:

c

运行

fgets(buf, ...); // 先写 printf("%s", buf); // 后读

完全正确,不用初始化!

http://www.jsqmd.com/news/822738/

相关文章:

  • 常见错误解析1.0
  • 【粉丝福利社】终于蹲到了!“能读一半就是赚到”的《编码》精装版来了
  • Charles+MuMu模拟器进行app抓包和调试教程
  • 【网安干货收藏】网络安全工程师速成完整版,小白 5 个月系统学习,轻松转行踏入高薪赛道
  • 2026年必看!超好用的上门做饭家政服务,让你轻松告别厨房烦恼 - 速递信息
  • Python_asyncio异步编程深度实战
  • 036、PCIE配置空间类型0与类型1:一次设备枚举失败的排查手记
  • 不争而胜:贾子竞争哲学的范式革命与终极法则
  • 6%AFFF水成膜泡沫灭火剂厂家推荐:浙江金瑞恒,卓越耐低温性能适配极端环境 - 品牌速递
  • AI编程助手背后的光标控制平面:语义化编辑的核心架构
  • Pytorch图像去噪实战(九十四):自动重训流水线,从反馈样本到新模型一键生成
  • 告别重复操作:M9A如何用智能自动化重塑《重返未来:1999》游戏体验
  • 告别命令行:实战ENSP Web界面配置防火墙与无线控制器
  • 主流LLM拓扑病理研究:形质混杂缺陷与二维扁平化智能存在的物理先天局限(世毫九实验室原创研究)
  • ARP协议深度解析:从原理到实战构建离线在线网络探测工具
  • 【大模型时代】产品经理为何必须学习大模型?产品经理必学!掌握大模型
  • 5G NR物理层实战:从帧结构参数到TB块生成的完整计算解析
  • 信号处理中的‘双子星’:深入对比周期信号的离散谱与非周期信号的连续谱(附Sinc函数详解)
  • 天津除甲醛公司及深度观察:直营服务如何应对北方供暖季挑战 - 博客湾
  • 农业AI智能体平台AgC:架构设计与核心技术解析
  • 基于Ansible与Docker的自动化家庭实验室构建指南
  • 2026无人机电力巡检公司盘点:按预算档怎么选 - 速递信息
  • 相机画幅对比
  • 2026年跨境POD定制系统选购指南:享定就定等主流方案深度对比 - 速递信息
  • 6%AFFF/AR抗溶性水成膜消防泡沫液厂家推荐:浙江金瑞恒,无惧极性溶剂挑战的灭火专家 - 品牌速递
  • 在多模型聚合平台Taotoken上如何进行高效的模型选型
  • HoRNDIS:Mac电脑通过Android手机USB共享上网的终极解决方案
  • 羽毛球单打战术
  • 射频高手到底强在哪里?尤其做5G,真正拼的是这套底层功夫
  • 新鲜出炉!2026银杏树培育基地推荐排行 高成活/全规格/一站式绿化服务 - 极欧测评