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

Linux 文件 I/O 与标准 I/O 缓冲机制详解

一、什么是标准 I/O?(FILE* 接口)

标准 I/O 是 C 标准库为我们提供的一套高级文件操作接口,核心基于结构体 FILE,常见函数如:

  • fopen() / fclose()

  • fread() / fwrite()

  • fprintf() / fscanf()

  • fflush() / fseek() / ftell()

其背后的设计理念是:在用户空间加一层缓冲区机制,减少频繁的系统调用,提高 I/O 效率


二、标准流与 FILE* 指针的关系

C 语言启动时自动打开的三个标准流:

名称

全局变量

描述

默认绑定设备

标准输入

stdin

键盘输入

文件描述符 0

标准输出

stdout

屏幕输出

文件描述符 1

标准错误输出

stderr

屏幕错误输出

文件描述符 2

它们本质上是三个全局变量指针:

extern FILE *stdin;   // 标准输入extern FILE *stdout;  // 标准输出extern FILE *stderr;  // 标准错误

它们都指向类型为 

FILE 的结构体对象,这些对象在程序启动时已经初始化好,不需要手动打开。

三、标准 I/O 的缓冲机制分类

标准 I/O 相比 read()/write() 的一个显著特点是:内部使用了缓冲区机制(缓解频繁的系统调用)

1. 无缓冲(Unbuffered)

  • 直接写入/读取,不做缓存。

  • 特征:每次 fputc()fprintf(stderr, ...) 都是一次系统调用。

  • 示例:标准错误流 stderr 通常是无缓冲。

2. 行缓冲(Line Buffered)

  • 读写一整行再提交,或者满足以下任一条件立即刷新:

    1. 遇到换行符 \n

    2. 调用 fflush()

    3. 缓冲区被填满

    4. 程序正常退出

  • 示例:标准输出 stdout 在连接终端时通常是行缓冲。

3. 全缓冲(Fully Buffered)

  • 只有当缓冲区满时或显示调用 fflush() 时才进行 I/O 操作。

  • 示例:对磁盘文件操作通常是全缓冲。

关于缓冲区的大小

标准 I/O 缓冲区大小(来自 APUE 的描述)

标准 I/O 使用的是 用户空间的缓冲机制,而这部分缓冲区的大小通常为:

✅ BUFSIZ,大小通常是 8192 字节(即 8KB)

  • BUFSIZ 是一个宏,定义在 <stdio.h> 中,表示标准库默认的缓冲区大小。

  • 实际大小由系统实现决定,但大多数现代系统中是 8192 字节(8KB)

  • 你可以通过下面代码查看具体大小​​​​​​​

#include <stdio.h>int main(){ printf("BUFSIZ = %d\n", BUFSIZ);  return0;}


 


🧠 说明一下:

  • 标准I/O函数(如 fopen/fread/fwrite)使用内部缓冲区,提高读写效率。

  • 这个缓冲区由 libc 实现,属于用户空间。

  • 不像 read() / write() 系统调用直接进入内核空间,标准IO通过一次性读写大块内容来减少系统调用次数。


🧪 补充说明:你还可以自己设定缓冲区​​​​​​​

FILE *fp = fopen("file.txt", "r");char buf[BUFSIZ];setbuf(fp, buf); // 手动设置缓冲区

或者使用 setvbuf() 函数精细控制缓冲类型(全缓冲、行缓冲、无缓冲)和大小。


📝 总结

名称

值(常见)

定义位置

用途

BUFSIZ

8192 字节

<stdio.h>

标准I/O默认缓冲区大小

📌 注意:BUFSIZ 是用于标准IO缓冲(如 fopen),而不是 read() 等系统调用(后者不涉及标准IO缓冲机制)。

这里FILE结构体需要描述

FILE 结构体的典型定义(简化版)

FILE 的真实定义是不公开的(属于 libc 实现细节),但你可以在 GNU libc 或 musl 的源码中看到类似的简化结构:​​​​​​​

typedef struct _IO_FILE {  int _fileno;            // 文件描述符,对应 open 返回的 int  char *_buffer;          // 指向缓冲区的指针  char *_bufpos;          // 当前缓冲位置  char *_bufend;          // 缓冲区末尾  int _flags;             // 文件状态,如可读、可写、错误、EOF 等  long _pos;              // 当前文件位置(用于 ftell、fseek)  // 还有更多复杂字段...} FILE;


 

📌注意:不同系统实现(如 glibc、musl)中,这个结构体的字段名称和结构会有所不同。


🎯 FILE 和底层文件描述符的区别

项目

FILE

(高级IO)

文件描述符(低级IO)

类型

FILE *

(结构体指针)

int

(整数)

接口

fopen

freadfwrite 等

open

readwrite 等

是否缓冲

✅ 有缓冲区(提高效率)

❌ 无缓冲(每次都直接系统调用)

是否格式化支持

✅ fprintffscanf

❌ 不支持格式化


🧠 标准流的 FILE 示例

C语言一开始默认打开了三个标准流(在 <stdio.h> 中定义):

extern FILE *stdin;   // 标准输入
extern FILE *stdout;  // 标准输出
extern FILE *stderr;  // 标准错误

你可以直接使用这些来读写数据:

fprintf(stdout, "Hello\n");
fscanf(stdin, "%d", &num);


🧪 进阶:缓冲机制与 FILE

  • FILE 内部包含了一个缓冲区,默认大小是 BUFSIZ(通常是 8192 字节)。

  • 分为:

    • 全缓冲(默认情况,大文件使用)

    • 行缓冲(用于终端)

    • 无缓冲(stderr)

你可以用 setvbuf() 或 setbuf() 控制缓冲方式。

http://www.lryc.cn/news/574471.html

相关文章:

  • Java面试中被深挖过的线程问题
  • 对手机屏中断路和短路的单元进行切割或熔接,实现液晶线路激光修复原理
  • Luckysheet Excel xlsx 导入导出互相转换
  • 02-Linux内核源码编译
  • CentOS 7 编译安装Nginx 1.27.5完整指南及负载均衡配置
  • MinIO中视频转换为HLS协议并进行AES加密
  • Python Polars库详解:高性能数据处理的新标杆
  • pyqt多界面
  • LangChain网页自动化PlayWrightBrowserToolkit
  • gRPC 静态库链接到 DLL 的风险与潜在问题
  • 鸿蒙开发深入解析:Service Ability(后台任务)全面指南
  • 深度解析|智能汽车操作系统技术突破:从架构演进到产业重构
  • 比翼双飞,影像的迁徙之旅
  • 基于目标驱动的分布式敏捷开发
  • GPPT(Graph Pre-training and Prompt Tuning)项目复现
  • 生成FUCK代币,并用程序进行转账的过程
  • C++字符串的行输入
  • 查询sqlserver数据库中,数据占的空间和索引占的空间
  • 鸿蒙HarmonyOS 5 开发实践:LazyForEach在通讯录应用中的高效渲染(附:代码)
  • 前端vue2每三十秒被动接受后端服务器发送过来得数据
  • 前端react使用 UmiJS 构建框架 在每次打包时候记录打包时间并在指定页面显示
  • Linux 启动过程流程图
  • PDF全能转换工具,支持图片转PDF,多图合并转PDF,word转PDF,PDF转WORD,PDF转图片
  • TouchDIVER Pro触觉手套:虚拟现实中的多模态交互新选择
  • Flask(五) 表单处理 request.form
  • 鸿蒙开发深入解析:Data Ability 数据共享机制全面指南
  • Java并发编程中高效缓存设计的哲学
  • 【格与代数系统】示例2
  • PyTorch 实现的 GlobalPMFSBlock_AP_Separate:嵌套注意力机制在多尺度特征聚合中的应用
  • 关于 pdd:anti_content参数分析与逆向