木下~Linux 系统编程笔记之文件 IO 与标准 IO
一、前置基础:带参数的 main 函数
带参 main 函数是文件操作程序的核心基础,用于程序运行时动态传入文件名、操作参数,无需硬编码,格式如下:
int main(int argc, char *argv[])
argc:命令行参数的总个数,程序名本身为第 1 个参数argv:字符串数组,存储每个命令行参数;argv[0]为程序名,argv[1]~argv[argc-1]为用户传入的自定义参数
二、文件 IO(系统调用级 IO)
1. 核心概述
文件 IO 是 Linux 原生的系统调用级 IO 函数,又称低级 IO,遵循 Linux一切皆文件的核心思想,可操作所有类型文件(普通文件、设备文件、管道、socket 等)。
2. 核心特性
- 无缓冲区:每次调用 IO 函数都会触发用户态与内核态的切换,频繁调用会降低读写效率
- 文件标识:文件描述符
int fd,非负整数,可用范围 0~1023 - 预打开的特殊描述符:程序运行自动打开,无需手动创建
- 0:标准输入(stdin),对应键盘
- 1:标准输出(stdout),对应终端
- 2:标准错误(stderr),对应终端
- 平台限制:仅适用于 UNIX/Linux 平台,不可跨标准 C 平台移植
- 描述符分配规则:优先使用当前可用的最小非负整数
3. 标准操作流程
打开文件(open)→ 操作文件(read/write/lseek)→ 关闭文件(close)
4. 核心 API 速查
表格
| 函数 | 核心原型 | 核心功能 | 参数要点 | 返回值规则 |
|---|---|---|---|---|
| open | int open(const char *pathname, int flags, mode_t mode); |
打开 / 创建文件,返回文件描述符 |
1. 2. 3. 4. |
成功:非负文件描述符失败:-1 |
| close | int close(int fd); |
关闭文件,释放文件描述符资源 | fd:待关闭的文件描述符 |
成功:0失败:-1 |
| read | ssize_t read(int fd, void *buf, size_t count); |
从文件读取数据到缓冲区 |
1. 2. 3. |
成功:实际读取到的字节数失败:-1文件末尾:0 |
| write | ssize_t write(int fd, const void *buf, size_t count); |
将缓冲区数据写入文件 |
1. 2. 3. |
成功:实际写入的字节数失败:-1 |
| lseek | off_t lseek(int fd, off_t offset, int whence); |
移动文件读写光标,改变读写位置 |
1. 2. |
成功:光标距文件开头的字节数失败:-1 |
5. 高频考点与必记规则
- 先写后读读不到内容的核心原因:写入完成后,光标停在文件末尾,需通过
lseek移动光标到目标位置才能读取。 - 经典用法:
- 先写后读:
lseek(fd, 0, SEEK_SET)回到文件开头再读取 - 获取文件大小:
lseek(fd, 0, SEEK_END),返回值即为文件总字节数
- 先写后读:
- 资源管理:文件描述符数量有限,使用完毕必须调用 close 关闭,否则会造成资源泄漏。
三、标准 IO(C 标准库 IO)
1. 核心概述
标准 IO 是 C 语言标准库在系统调用之上封装的 IO 函数,又称高级 IO,核心优化是增加了缓冲区机制,主要用于操作普通文件,可跨所有标准 C 平台移植。
2. 核心特性
- 带缓冲区:减少用户态与内核态的切换次数,批量读写数据,读写效率远高于无缓冲的文件 IO
- 文件标识:文件流指针
FILE *fp,非空指针标识打开的文件 - 预打开的特殊流指针:程序运行自动打开,
stdin(标准输入)、stdout(标准输出)、stderr(标准错误) - 跨平台性:兼容所有标准 C 平台,可移植性极强
- 适用范围:主要用于普通文件操作,无法直接操作设备文件、管道等特殊文件
3. 核心重点:缓冲区机制(与文件 IO 的核心区别)
标准 IO 根据使用场景分为两类缓冲区,刷新规则是高频必记考点:
| 缓冲区类型 | 适用场景 | 自动刷新条件 |
|---|---|---|
| 行缓冲 | 标准输入 (stdin)、标准输出 (stdout) |
1. 程序正常执行结束 2. 流指针被 fclose 关闭 3. 缓冲区被填满(默认 1K) 4. 写入内容包含换行符 5. 主动调用 fflush () 刷新 |
| 全缓冲 | 磁盘普通文件 |
1. 程序正常执行结束 2. 流指针被 fclose 关闭 3. 缓冲区被填满(默认 4K) 4. 主动调用 fflush () 刷新⚠️ 遇 |
4. 标准操作流程
打开文件(fopen)→ 操作文件(各类读写函数)→ 关闭文件(fclose)
5. 核心 API 速查
5.1 打开 / 关闭文件
| 函数 | 核心原型 | 核心功能 | 参数要点 | 返回值规则 |
|---|---|---|---|---|
| fopen | FILE *fopen(const char *pathname, const char *mode); |
打开 / 创建文件,返回流指针 |
1. 2. |
成功:非空 FILE * 流指针失败:NULL |
| fclose | int fclose(FILE *stream); |
关闭文件流,刷新缓冲区,释放资源 | stream:待关闭的文件流指针 |
成功:0 |
5.2 四大类读写函数
| 读写类型 | 核心函数 | 核心原型 | 功能与关键特性 | 返回值规则 |
|---|---|---|---|---|
| 块读写 | fread | size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream); |
以数据块为单位读取文件,遇空格 / 换行不结束,适合二进制文件、大数据块读写 | 成功:实际读取的完整块数量失败 / 文件末尾:0 |
| fwrite | size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream); |
以数据块为单位写入文件 | 成功:实际写入的完整块数量失败:0 | |
| 格式读写 | fscanf | int fscanf(FILE *stream, const char *format, ...); |
按指定格式读取文件,用法与 scanf 完全一致,scanf等价于fscanf(stdin, ...) |
成功:成功读取的变量个数失败 / 文件末尾:小于格式控制符数量 |
| fprintf | int fprintf(FILE *stream, const char *format, ...); |
按指定格式写入文件,用法与 printf 完全一致,printf等价于fprintf(stdout, ...) |
成功:写入的字节数失败:负数 | |
| 字符读写 | fgetc | int fgetc(FILE *stream); |
读取文件的单个字符 | 成功:读取到的字符失败 / 文件末尾:EOF (-1) |
| fputc | int fputc(int c, FILE *stream); |
向文件写入单个字符 | 成功:写入的字符失败:EOF | |
| 行读写 | fgets | char *fgets(char *s, int size, FILE *stream); |
按行读取文件,遇换行结束,换行符会被读取,最多读 size-1 个字节,末尾自动补 '\0' | 成功:存储内容的缓冲区首地址失败 / 文件末尾:NULL |
| fputs | int fputs(const char *s, FILE *stream); |
向文件写入一行字符串,不自动添加换行符 | 成功:写入的字节数失败:EOF |
5.3 辅助操作函数
| 函数 | 核心原型 | 核心功能 | 高频用法 |
|---|---|---|---|
| fseek | int fseek(FILE *stream, long offset, int whence); |
移动文件读写光标,参数规则同 lseek | 先写后读:fseek(fp, 0, SEEK_SET) 回到文件开头 |
| fflush | int fflush(FILE *stream); |
主动刷新缓冲区,将缓冲区数据写入底层 | printf 无 \n 时,fflush(stdout)强制打印到终端 |
| feof | int feof(FILE *stream); |
判断文件是否到达末尾 | 循环读取文件时,判断读取结束条件,到达末尾返回非 0 |
6. 必记规则
- 先写后读读不到内容:写入完成后光标停在文件末尾,需通过
fseek移动光标到目标位置再读取。 - 写入文件后看不到内容:全缓冲模式下,缓冲区未填满 / 未关闭 / 未主动刷新,数据仍在缓冲区,未写入磁盘,可通过
fflush强制刷新。 fscanf遇空格自动跳过,适合读取格式化文本;fgets会读取换行符,使用时需注意处理末尾的\n。
四、文件 IO 与标准 IO 核心对比表
| 对比维度 | 文件 IO | 标准 IO |
|---|---|---|
| 本质 | Linux 系统调用,内核级操作 | C 标准库封装,在系统调用之上的用户态封装 |
| 缓冲区 | 无缓冲区,每次调用都触发内核态切换 | 有行缓冲 / 全缓冲,减少内核态切换,效率更高 |
| 文件标识 | 文件描述符 int fd | 文件流指针 FILE *fp |
| 适用范围 | 所有 Linux 文件类型(普通文件、设备、管道、socket 等) | 主要用于普通文件,无法直接操作特殊设备文件 |
| 跨平台性 | 仅适用于 UNIX/Linux 平台 | 兼容所有标准 C 平台,可移植性强 |
| 操作粒度 | 字节级读写,灵活度高 | 支持块、格式、字符、行多种读写模式,开发更便捷 |
| 效率 | 频繁调用效率低,单次大数据读写效率尚可 | 批量读写效率远高于文件 IO,频繁小数据读写优势显著 |
更多推荐




所有评论(0)