欢迎光临
我们一直在努力

软件编程 | 标准IO编程

1、IO编程

1.1 IO概念

I:   Input(输入)

O:Output(输出)

 是指计算机与外部设备之间的数据交互过程,是程序与外部环境交换数据的核心方式。

IO操作的对象是文件

1.2 一切皆是文件

文件类型:

b        block                块设备文件                     代表块存储设备,如硬盘、U 盘

系统以数据块为单位读写数据,按块扫描信息的文件

c        character          字符设备文件                 代表字符流设备,如键盘、鼠标、串口、终端系统以单个字符为单位流式读写,按字符扫描信息的文件

d        directory            目录文件

存放文件或子目录信息的文件夹

–        regular                普通文件

用于存储各类数据,无固定结构,可存放文本、二进制、压缩包、源码等任意数据

l        link                     链接文件

将一个文件链接到另一个文件,分为  软链接(符号链接) 和硬链接

软链接 = 快捷方式,硬链接 = 文件的别名 / 分身

限制:软链接可跨文件系统、可链接目录;硬链接不可跨文件系统、不可链接目录

  • 软链接(l):独立文件,存储目标路径,删除原文件后软链接失效;
  • 硬链接:无独立标识(显示为-),和原文件共用 inode,删除原文件不影响访问
  • inode:系统分配的唯一数字编号,存储文件的元数据(权限、大小、存储位置、引用计数等),相当于文件的身份证号;
  • 引用计数机制:inode 中有个链接计数,每创建一个硬链接,计数 + 1;删除一个链接(文件名),计数 – 1;只有计数归 0 时,系统才会真正删除文件数据
  • 文件名:只是指向 inode 的标签 / 别名,用户通过文件名找到 inode,进而访问文件数据
  • 系统判断两个文件是不是同一个文件,不看名字,只看 inode 号是否相同
  • # 查看inode和详情         ls -li

s       socket                套接字文件

用于本地进程间通信(IPC),也可实现网络通信,支持双向数据传输,效率高于管道,常见于系统服务(如 MySQL)

p        pipe                    管道文件

用于本地进程间单向通信,分为匿名管道和命名管道,数据单向流动,先进先出(FIFO),读写阻塞式传输

1.3 IO的接口分类

分类操作对象核心特点依赖库 / 接口
标准 IO(stdio) 普通磁盘文件 有缓存的IO;用户态缓存,减少系统调用次数,效率高,跨平台性好 C 标准库(stdio.h)
文件 IO(系统调用) 设备文件、网络通信、特殊文件 没有缓存的IO;无用户态缓存,直接与内核交互(直接调用内核 syscall),实时性强,平台相关 Linux 系统调用(open/read/write)
目录 IO 目录文件 专用接口,仅用于遍历 / 操作目录结构 dirent.h 系统头文件

2、标准IO

标准 IO 是C 语言标准库提供的 IO 操作接口,封装了底层系统调用,自带用户态缓冲区,适配所有支持 C 标准库的操作系统,是操作普通文件的首选方案。

2.1 标准IO头文件

所有标准 IO 函数均依赖该头文件,无其他额外依赖

#include <stdio.h>

2.2 核心接口分类

功能分类函数接口
文件开关 fopen(打开)、fclose(关闭)
单字符读写 fgetc(读单个字符)、fputc(写单个字符)
字符串读写 fgets(读一行字符串)、fputs(写字符串)
格式化读写 fscanf(格式化读)、fprintf(格式化写)
二进制数据读写 fread(块读)、fwrite(块写)
文件定位 fseek(偏移定位)、rewind(回到文件头)、ftell(获取当前偏移)
缓冲区控制 fflush(刷新缓冲区)、setvbuf(设置缓冲区模式)

2.3 普通文件类型分类

(1)文本文件(ASCII 码文件):

  • 存储内容:文件中存放的内容均为能够在终端显示的ASCII码字符
  • 典型场景:代码源文件、配置文件、文本文件;
  • 特点:可直接用文本编辑器打开查看。

(2)二进制文件

  • 存储内容:存放二进制数据本身的文件(无字符编码转换);
  • 典型场景:图片、音视频、可执行程序、压缩包;
  • 特点:无法直接用文本编辑器正常解析,存储效率更高。

注意:ASCII码文件是一种特殊的二进制文件,二者本质都是二进制存储,区别仅在于数据编码规则和解析方式。

2.4 标准IO核心操作流程

打开文件:fopen 获取文件流指针(FILE*),建立程序与文件的关联;

数据交互:通过读写接口完成文件的读 / 写操作;

关闭文件:fclose 释放资源,刷新缓冲区,断开关联。

2.5 Linux/C 语言默认打开的流(与终端建立的流)

  • stdin(标准输入流):文件描述符 0,默认从键盘/终端读取

  • stdout(标准输出流):文件描述符 1,默认输出到终端

  • stderr(标准错误流):文件描述符 2,默认输出到终端

2.6 三种缓存类型

缓存的核心作用:减少磁盘 I/O/ 系统调用次数,提升程序运行效率,不同缓存策略适配不同使用场景。

 (1)全缓存:(Full Buffering)4096(4k)

  • 缓存区大小:Linux/glibc (通用库)默认约4096 字节(磁盘 IO 块大小常用值)
  • 核心特性:缓存区写满后才统一刷新,是效率最高的缓存策略
  • 刷新触发条件:
  • 缓存区写满,自动刷新;
  • 程序正常退出;
  • 调用fclose()关闭流;
  • 调用fflush()手动强制刷新;
  • 无换行符触发机制(和行缓存核心区别)
  • 默认适用对象:stdin/stdout 重定向到普通文件时、所有通过fopen打开的普通文件流
  • 典型场景:文件读写、批量写入减少 I/O 开销等

(2)行缓存:(Line Buffering)

  • 缓存区大小:Linux/glibc 默认约1024 字节(非标准强制规定)
  • 核心特性:以换行符 \\n 为触发刷新的核心标识
  • 刷新触发条件:
  • 缓存区写满,自动刷新;
  • 程序正常退出(main执行完毕);
  • 调用fclose()关闭流;
  • 调用fflush()手动强制刷新;
  • 遇到换行符 \\n,立即刷新缓存区。
  • 默认适用对象:stdin/stdout 连接终端时
  • 典型场景:终端交互(命令行输出、用户输入),保证信息逐行实时显示

(3) 无缓存(No Buffering)

  • 缓存区大小:0 字节,无临时存储区域
  • 刷新规则:数据立即写入目标设备 / 文件,不做任何缓冲
  • 强制刷新条件:无需手动刷新,写入即输出
  • 默认适用对象:stderr(标准错误流,固定无缓存)
  • 典型场景: 用于错误处理或者人机交互

3、核心函数接口

3.1 fopen—-打开文件,建立文件流

3.1.1 函数原型

FILE *fopen(const char *pathname, const char *mode);

3.1.2 功能

打开指定路径的文件,创建并返回文件流指针,建立程序与文件之间的数据通道

3.1.3 参数

参数名说明
pathname 文件路径(相对路径 / 绝对路径) 「文件所在的位置」 + 「文件名」
mode 文件打开模式,决定读写权限、文件创建 / 截断行为

3.1.4 打开模式详解

模式含义文件不存在文件已存在读写权限
r 只读打开(文本模式) 报错 正常打开 只读,从文件头部开始读取
w 只写打开,清空原有内容 创建新文件 清空重写 只写,从头部写入
a 追加只写(末尾添加) 创建新文件 保留内容 只写,写入位置固定在文件末尾,不会覆盖原有内容
r+ 读写打开,从文件开头操作 报错 正常打开 可读可写
w+ 写读打开,文件存在则清空原有内容 创建新文件 清空重写 可读可写
a+ 读写打开,仅支持末尾追加 创建新文件 保留内容 可读可写,写入固定在末尾,读取可任意位置

补充:模式后加b(如rb/wb)表示二进制模式,Linux 系统下文本 / 二进制模式无差异,Windows 系统下会自动转换换行符。

3.1.5 返回值

  • 成功:返回指向文件流的FILE*指针(流的首地址)
  • 失败:返回NULL

3.2 fclose—关闭文件流

3.2.1 函数原型

int fclose(FILE *stream);

3.2.2 功能

关闭文件流,刷新缓冲区剩余数据,释放系统资源,断开程序与文件的关联。

重要:文件操作完成后必须调用fclose,避免数据丢失、文件句柄泄漏

3.2.3 参数

stream:通过fopen获取的文件流指针

3.2.4 返回值

  • 成功:返回0
  • 失败:返回EOF(宏定义,值为-1)

3.3 fputc—写入单个字符

 3.3.1 函数原型

int fputc(int c, FILE *stream);

3.3.2 功能

向指定文件流中写入一个字符,写入后文件位置指针自动后移一位。

3.3.3 参数

参数说明
c 待写入的字符(会被转换为unsigned char)
stream 目标文件流指针

3.3.4 返回值

  • 成功:返回写入字符的ASCII码值(无符号字符形式)
  • 失败:返回EOF(-1)

// 向标准输出(终端)打印字符,二者完全等价
putchar(c); // 标准库宏/函数
fputc(c, stdout);

3.4 fgetc—读取单个字符

 3.4.1 函数原型

int fgetc(FILE *stream);

3.4.2 功能

从指定文件流中读取一个字符,读取后文件位置指针自动后移一位。

3.4.3 参数

stream:源文件流指针

3.4.4 返回值

  • 成功:返回写入字符的ASCII码值(无符号字符形式)
  • 失败:返回EOF(-1)

注意:返回值用int接收,用于区分有效字符和EOF(-1)

// 从标准输入(键盘)读取字符,二者完全等价
getchar();
fgetc(stdin);

3.5 fputs—写入字符串(无换行)

3.5.1 函数原型

int fputs(const char *s, FILE *stream);

3.5.2 功能

将以\\0结尾的字符串写入指定文件流,不会自动写入字符串结束符\\0,也不会自动添加换行符。

3.5.3 参数

参数说明
s 待写入的字符串首地址
stream 目标文件流指针

3.5.4 返回值

  • 成功:返回非负整数(通常为0)
  • 失败:返回EOF(-1)

// 向终端输出字符串,二者不完全等价
puts(s); // 会自动在末尾添加换行符
fputs(s, stdout);// 不会自动添加换行符

3.6 fgets—读取指定长度字符串

3.6.1 函数原型

char *fgets(char *s, int size, FILE *stream);

3.6.2 功能

从指定文件流中读取最多size-1个字符,存储到s指向的缓冲区,自动在末尾添加字符串结束符\\0;遇到换行符\\n 或文件末尾时提前停止读取。

参数

表格

参数说明
s 存储读取数据的缓冲区首地址
size 缓冲区最大容量(读取长度 = size-1)
stream 源文件流指针

返回值

  • 成功:返回缓冲区指针s
  • 读到文件末尾 / 失败:返回NULL

3.7 fprintf—格式化写入文件流

3.7.1 函数原型

int fprintf(FILE *stream, const char *format, …);

3.7.2 功能

按指定格式向文件流中写入字符串 / 数据(类似printf,但输出目标是文件流而非终端)。

3.7.3 参数

参数说明
stream 目标文件流指针(如stdout输出到终端,fp输出到文件)
format 格式控制字符串(和printf完全一致,如%d/%s/%f)
可变参数,对应格式字符串中的占位符(如fprintf(fp, "%d", 10)中的10)

3.7.4 返回值

  • 成功:返回实际写入的字符总数
  • 失败:返回负数(通常为-1)

示例:

// 向文件写入格式化数据
fprintf(fp, "姓名:%s,年龄:%d\\n", "张三", 20);
// 向终端输出(等价于printf)
fprintf(stdout, "计算结果:%f\\n", 3.1415);

3.8 fscanf—格式化读取文件流

3.8.1 函数原型

int fscanf(FILE *stream, const char *format, …);

3.8.2  功能

按指定格式从文件流中读取数据(类似scanf,但读取源是文件流而非键盘)。

3.8.3 参数

参数说明
stream 源文件流指针(如stdin从键盘读取,fp从文件读取)
format 格式控制字符串(和scanf完全一致,如%d/%s/%f)
可变参数,接收数据的变量地址(如fscanf(fp, "%d", &age)中的&age)

3.8.4 返回值

  • 成功:返回成功匹配并读取的参数个数
  • 失败 / 读到文件末尾:返回EOF(-1)

示例:

char name[20];
int age;
// 从文件读取姓名和年龄
fscanf(fp, "%s %d", name, &age);
// 从键盘读取(等价于scanf)
fscanf(stdin, "%d", &age);

赞(0)
未经允许不得转载:171主机测评 » 软件编程 | 标准IO编程
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址