1. IO概述
IO 指的是输入输出函数。
站在计算机的角度,输入是读操作,输出是写操作。
例如:我们从终端输入信息给计算机,计算机是从终端读取信息,而我们让计算机输出信息时,计算机是要向终端写信息。
IO分为文件IO和标准IO
- 文件IO属于系统调用
- 标准IO属于库函数
系统调用和库函数有什么区别?
系统调用:用户通过应用层函数操作Linux内核,Linux内核再控制硬件。
Linux内核中封装了大量的系统调用,用户通过应用层的系统调用函数调用内核中的系统调用。
因为不同的Linux内核中的系统调用是不同的,所以采用系统调用的应用程序移植性不高,而对底层硬件的操作一般都是用的系统调用
库函数:库函数本质还是系统调用,但比系统调用多了一个缓冲区,缓冲区用来减少系统调用次数,只有在缓冲区被刷新的时候,才会执行系统调用。
库函数是为了统一不同操作系统对文件操作的函数,只要支持C语言,库函数一般就可以使用,所以库函数的移植性更高。
库函数调用 | 系统调用 | |
---|---|---|
移植性 | 可移植性好 | 依赖内核,不保证移植性 |
调用属性 | 调用函数库的代码 | 调用系统内核的服务 |
调用类型 | 普通函数的调用 | 操作系统的入口点 |
运行空间 | 用户空间执行 | 内核空间执行 |
运行时间所属 | 用户时间 | 系统时间 |
开销 | 属于过程调用,开销较小 | 在用户空间和内核空间上下文环境切换,开销较大 |
数量 | 库函数数量多 | Unix大约有90个系统调用,较少 |
典型调用函数 | printf scanf malloc |
fork open write |
对硬件进行操作时,会先操作Linux内核
操作Linux内核的三种方式:shell、系统调用、库函数。
2. 标准IO
2.1 缓冲区 / 缓存区
分类 | 解释 |
---|---|
行缓冲 | 终端操作对应的缓冲区为行缓冲 |
全缓冲 | 文件操作对应的缓冲区为全缓冲 |
无缓冲 | 终端输出错误信息对应的缓冲区为无缓冲 |
缓冲区需要被刷新,如果不刷新缓冲区,数据就停留在缓冲区,无法执行系统调用。
向无缓冲写入数据会直接打印在终端
行缓冲区刷新方法
- 输出
\n
- 缓冲区切换 (输出缓冲转换成输入缓冲)
- 使用
fflush
函数,刷新缓冲区 - 缓冲区满时,行缓冲大小为
1024 Bytes
- 程序正常结束
全缓冲区刷新方法
- 使用
fflush
函数 - 缓冲区满
- 程序正常结束
2.2 文件指针
文件指针又称为流指针,简称流。(stream pointer
)
可以理解为向文件读取或者写入信息时,那些字符像流水一样有序地流出或者流入。
文件指针标识一个文件,用库函数对文件操作时,需要用到文件指针。
文件指针是结构体类型指针FILE *
,typedef struct _IO_FILE FILE;
_IO_FILE
结构体中,保存了打开的文件的各种信息
程序运行时,操作系统会自动为当前程序分配三个文件指针
FILE * |
作用 |
---|---|
stdin |
标准输入流指针,用于从终端读取数据 |
stdout |
标准输出流指针,用于对终端写数据 |
stderr |
标准错误输出流指针,用于向终端输出错误信息 |
2.3 标准IO常用函数
fopen()
fopen
不仅打开一个文件,还会创建缓冲区——如果是读写模式,打开两个;只读或者只写,则只打开一个,再创建一个包含文件和缓冲区数据的结构体。
以文本模式打开,返回的就是文本流
以二进制模式打开,返回的就是二进制流
#include <stdio.h>
FILE *fopen(const char *pathname, const char *mode);
功能:打开或者创建一个文件
参数:
pathname:
要打开或者创建的文件名,可以跟路径,如果不跟路径,默认就是当前路径
mode:操作权限
r 以只读的方式打开,如果文件不存在则报错,文件指针定位到文件的起始位置
r+ 以读写的方式打开,如果文件不存在则报错,文件指针定位到文件的起始位置
以 "r" 或者 "r+" 打开,文件不存在,返回错误码为 2 。
w 以只写的方式打开,如果文件存在则清空,文件不存在则创建,文件指针定位到文件的起始位置
w+ 以读写的方式打开,如果文件存在则清空,文件不存在则创建,文件指针定位到文件的起始位置
a 以只写的方式打开,如果文件存在则追加,文件不存在则创建,文件指针定位到文件的起末尾位置
a+ 以读写的方式打开,如果文件存在则追加,文件不存在则创建,文件指针定位到文件的起末尾位置
在 r / w / a 后面加上 b 就代表以二进制方式打开文件
w 后面加上 x (c11)如果文件已存在或以独占模式打开文件,则打开文件失败
返回值:
成功:文件指针
失败:NULL
使用a+
操作时,无论读到文件哪个位置,执行写操作时,都会在文件结尾处追加。
fclose()
#include <stdio.h>
int fclose(FILE *stream);
功能:
关闭一个文件指针,如果关闭了文件指针,就无法再通过这个文件指针对文件进行操作了
参数:
stream:文件指针,fopen的返回值
返回值:
成功:0
失败:EOF
EOF
→end of file
文件结束描述符,一般值为-1
perror()
#include <stdio.h>