如果不知道inode,请看这篇文章inode
我们知道当打开一个文件时,OS会先使用inode编号在磁盘文件系统里面去寻找这个文件,找到以后根据文件的属性为其创建一个内核层面的结构体来描述这个文件,该结构体里面含有文件的属性信息(大小,拥有者,创建修改时间)。当我们上层用户要对文件进行操作时,一定是需要使用系统调用函数(open,write,,read,close等等)依赖操作系统来进行操作,这些函数是底层用于文件I/O的)。为了提供比底层系统调用更为方便、好用的调用接口,设计了标准I/O库函数(fopen,fwrite,fread,fclose,fflush等等),使用时需要包含头文件<stdio.h>。
对于标准 I/O 库函数来说,它们的操作是围绕 FILE 指针进行的,当使用标准 I/O 库函数打开或创建一个文件时,会返回一个指向 FILE 类型对象的指针,使用该 FILE 指针与被打开或创建的文件相关联,然后该 FILE 指针就用于后续的标准 I/O 操作(使用标准 I/O 库函数进行 I/O 操作),所以由此可知,FILE 指针的作用相当于文件描述符,只不过 FILE 指针用于标准 I/O 库函数中、而文件描述符则用于文件 I/O 系统调用中。
FILE 是一个结构体数据类型,它包含了标准 I/O 库函数为管理文件所需要的所有信息,包括用于实际 I/O 的文件描述符、指向文件缓冲区的指针、缓冲区的长度、当前缓冲区中的字节数以及出错标志等。FILE 数据结构定义在标准 I/O 库函数头文件 <stdio.h> 中。
FILE结构体如下图
通过上面两图可以看到,stdin其实就是一个结构体FILE* 指针。
在操作系统层面,当一个进程被启动时,进程会默认打开0,1,2号文件描述符对应标准输入设备文件,标准输出设备文件,标准错误设备文件,这些设备也相当于文件。
在用户(开发者)层面,标准 I/O
库中,使用 stdin
、stdout
、stderr
来表示标准输入、标准输出和标准错误,它们都是FILE结构体指针,都有一个文件描述符,所以我们才可以通过库函数调用系统函数来对文件进行操作。当我们使用fopen函数打开一个文件时,返回函数就是FILE*类型指针,因为在标准I/O层面,无法使用文件描述符进行文件操作。