“标准 I/O 用 fopen,底层控制用 open; 要 mmap 必 open,跨平台选 fopen。”

📌 一句话总结

open() / read() / write() / close() fopen() / fread() / fwrite() / fclose()
所属层级 系统调用(System Call) ------ 内核接口 标准 C 库函数(Standard I/O) ------ 用户库封装
头文件 <fcntl.h>, <unistd.h> <stdio.h>
返回类型 int(文件描述符,file descriptor) FILE*(文件流指针)
缓冲机制 无缓冲(每次调用都陷入内核) 带缓冲(减少系统调用次数,提高效率)
可移植性 类 Unix 系统(Linux/macOS/WSL),非 ANSI C ANSI C 标准,跨平台(Windows/Linux/macOS)
适用场景 高性能、底层控制、设备文件、mmap 一般文件读写、文本处理、快速开发

🔍 详细对比

1. 层级与实现

  • open() 系列

    • 操作系统提供的系统调用,直接与内核交互。
    • 每次 read()/write() 都会触发一次 系统调用(syscall) ,开销较大。
  • fopen() 系列

    • C 标准库(如 glibc)对系统调用的封装
    • 内部使用缓冲区(通常 4KB~8KB),只有缓冲区满或显式刷新(fflush)时才调用 write()

✅ 举例:

fwrite() 写 1000 次 1 字节 → 可能只触发 1 次 write() 系统调用。

write() 写 1000 次 1 字节 → 触发 1000 次 系统调用(慢!)。


2. 缓冲机制(关键区别!)

函数系列 缓冲类型 行为
fopen 全缓冲(文件) / 行缓冲(终端) 数据先存入 FILE* 的内部缓冲区
open 无缓冲 数据直接传给内核
scss 复制代码
// 标准 I/O:可能看不到立即输出
FILE *fp = fopen("log.txt", "w");
fprintf(fp, "Hello");  // 数据在缓冲区,未写入磁盘!
// 需要 fclose(fp) 或 fflush(fp) 才真正写入

// 系统调用:立即写入
int fd = open("log.txt", O_WRONLY | O_CREAT, 0666);
write(fd, "Hello", 5);  // 立即进入内核,写入磁盘(或 page cache)

3. 返回值与错误处理

返回值 错误检查方式
open fd(≥0 成功,-1 失败) 检查返回值是否为 -1,用 errnoperror()
fopen FILE*(非 NULL 成功,NULL 失败) 检查是否为 NULL,用 perror()

4. 功能与灵活性

能力 open() 系列 fopen() 系列
打开设备文件(如 /dev/tty ✅ 支持 ⚠️ 可能支持,但不推荐
非阻塞 I/O、异步 I/O ✅ 支持(配合 O_NONBLOCK 等) ❌ 不支持
mmap() 配合使用 ✅ 必须用 open()mmap 需要 fd ❌ 不能直接用(需 fileno() 转换,不推荐)
文本模式自动换行转换(Windows) ❌ 无 "r"/"w" 模式自动处理 \n\r\n
格式化输入输出(printf/scanf ❌ 无 ✅ 支持 fprintf, fscanf

5. 性能对比(典型场景)

场景 推荐使用
读写大文件(如 1GB 视频) 两者均可,open + 大块 read 更可控
频繁小量写入(如日志) fopen(缓冲减少 syscall)
需要 mmapfcntlioctl ✅ 必须用 open
跨平台程序(Windows + Linux) fopen(标准 C)
实时性要求高、避免缓冲延迟 open(或 setvbuf 关闭缓冲)

🔄 如何互相转换?

虽然不推荐混用,但技术上可行:

ini 复制代码
#include <stdio.h>
#include <unistd.h>

FILE *fp = fopen("test.txt", "w");
int fd = fileno(fp);        // FILE* → fd

int fd2 = open("test2.txt", O_WRONLY | O_CREAT, 0666);
FILE *fp2 = fdopen(fd2, "w"); // fd → FILE*

⚠️ 注意:混用可能导致缓冲不一致(如先 write(fd)fwrite(fp)),强烈建议不要混用同一个文件


✅ 总结:如何选择?

你想要...... 用哪个?
快速读写文本文件、做作业、写小程序 fopen 系列(简单、安全、标准)
使用 mmap()、控制文件锁、操作设备 open 系列(底层、灵活)
最高性能(自己管理缓冲) open + 大块 read/write
跨平台兼容性 fopen
确保数据立即写入磁盘 open + fsync(),或 fopen + fflush() + fsync(fileno(fp))

💡 记住这个口诀:

"标准 I/O 用 fopen,底层控制用 open
mmapopen,跨平台选 fopen。"

相关推荐
刺客xs3 分钟前
linux GDB调试器
linux·运维·windows
wydaicls1 小时前
Linux 内核伙伴系统在快速路径分配内存时,对一个内存区域(Zone)进行水位线检查和内存压力评估的关键逻辑
linux·服务器
今天只学一颗糖2 小时前
Linux学习笔记--GPIO子系统和PinCtrl子系统
linux·笔记·学习
黄昏晓x2 小时前
Linux----权限
linux·运维·服务器
小白不想白a2 小时前
【shell】每日shell练习(系统服务状态监控/系统性能瓶颈分析)
linux·运维·服务器
一匹电信狗2 小时前
【MySQL】数据库的相关操作
linux·运维·服务器·数据库·mysql·ubuntu·小程序
bugtraq20213 小时前
为什么.NET的System.IO.Compression无法解压zlib流
linux·运维·服务器
咖啡教室3 小时前
每日一个计算机小知识:Linux
linux·后端
江公望5 小时前
Qt的QT_QPA_EGLFS_INTEGRATION环境变量浅解
linux·qt·qml
YuCaiH5 小时前
网络编程的基础知识
linux·笔记·嵌入式·网络通信