Linux:标准IO

发布时间:2026/5/15 16:15:34

Linux:标准IO 标准IO概念Linux操作系统分层结构结构应用层 应用程序 app appC库函数 标准IO内核层 系统调用文件IO内核驱动硬件层 硬件标准IO系统调用能提供给内核层与用户层打交道的接口标准IOIO概述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);fopentest.c,w//文件以只写的方式打开如果文件不存在则会创建文件//如果文件存在则会清空文件fopen(test.c,r) //以只读的方式打开文件如果文件不存在则会进行报错文件存在就打印成功不存在的情况包括路径不对或文件名错误的问题fopen(test.c,a) //以追加的方式打开文件如果文件不存在创建文件//如果文件存在不会清空文件的原有内容//联合fprintf、fput、fwrite写入1fprintf打印的是写给人看的文本它是用来追加文本的称为格式化文本输出函数f2write是写入的二进制文件写在.c的代码中时乱码写文件必须是文本写入模式与格式化输出函数结合使用才能追加fwrite只能写入二进制文件写入模式为-ab,写入data.bin,而不是test.c或text.h它的格式与fprintf都不同格式如下int numbers[] {10, 20, 30};//参数含义(数据源, 单个元素大小, 元素个数, 文件指针)fwrite(numbers, sizeof(int), 3, fp);3fputs写入的是纯文本内核中的错误码问题错误码转换为错误信息-strerror函数也称转换函数错误码是1,2...等数字各代表一种错误如何把错误码转换成错误信息即字符串的文本信息用到了strerror函数这个函数定义在string.h这个头文件里直接引用错误信息打印函数-perror函数直接显示错误不转换perror函数在头文件stdio.hperror(文件打开失败);//用这个而不用没有提示的运行结果如图//我们在使用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当文件关闭时文件指针流关闭时刷新缓冲区fclose4当输入与输出进行切换时刷新缓冲区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会做两件事把文件内容放进 buf自动在最后加\0→ 覆盖了所有垃圾→ 完全安全4. 最关键的规则背下来谁先使用谁负责初始化先读使用→ 必须初始化先写覆盖→ 不需要初始化你现在的代码c运行fgets(buf, ...); // 先写 printf(%s, buf); // 后读✅完全正确不用初始化

相关新闻