目录
1.文件接口
1.1open
1.2C语言为什么要对open进行封装
2.fd
demo代码
第一个问题
第二个问题
打开文件流程
引言:在学习C语言的时候,我们见过很多的文件的接口,例如fopen,fwrite,fclose等等,但是仅仅凭借C语言的知识,我们并没有办法完全理解,只是知道怎么去用,希望看完这篇文章能加深你对文件的理解。
1.文件接口
C语言的各种的文件接口,必然是对系统调用的封装,打开一个文件必须,先将其加载到内存,这只有操作系统才能做到。
1.1open
返回值:打开或者创建新文件的fd(file descriptor)文件描述符,为什么是int,后面会讲。
pathname:打开或者创建文件的名字。
flag:打开方式(利用位图传参)
O_RDONLY以只读的方式打开
O_WRONLY以只写的方式打开
O_RDWR以读写的方式打开
O_APPEND以追加的方式打开
O_CREAT如果文件不存在,就创建个新文件
O_TRUNC打开时将文件清空
mode:新创建文件的权限,受权限掩码影响。
其实这里已经很明显了,fopen("xxx","w")就是open("xxx",O_WRONLY | O_CREAT | O_TRUNC)
1.2C语言为什么要对open进行封装
因为不同平台的open接口是不同的,将open封装,保证了C语言的跨平台性,fopen调用不同平台的open接口。
2.fd
demo代码
#include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> int main() { umask(0);//权限掩码设置为0 int fd1 = open("log1.txt", O_WRONLY|O_CREAT|O_TRUNC, 0666); int fd2 = open("log2.txt", O_WRONLY|O_CREAT|O_TRUNC, 0666); int fd3 = open("log3.txt", O_WRONLY|O_CREAT|O_TRUNC, 0666); int fd4 = open("log4.txt", O_WRONLY|O_CREAT|O_TRUNC, 0666); if(fd == -1) { perror("open"); return 1; } printf("fd: %d ", fd1); printf("fd: %d ", fd2); printf("fd: %d ", fd3); printf("fd: %d ", fd4); }
创建了文件,并且把他们fd全部打印出来。
执行结果
看到这个执行结果有2个问题
1.0 1 2去哪里了
2.fd有些像数组下标
第一个问题
0 1 2是程序默认打开的三个文件流
stdin: 0 标准输入 键盘设备
stdout:1 标准输出 显示器设备
stderr:2 标准错误 显示器设备
printf("%d ", stdin->_fileno); printf("%d ", stdout->_fileno); printf("%d ", stderr->_fileno);
第二个问题
stdin的类型是FILE * ,很明显stdin是一个结构体指针,说明LINUX系统内核中存在一种结构体,来描述文件。
struct file 就是对文件的描述,每个struct file都会存在一个struct file*next 指向下个struct file,操作系统就把对文件的管理,转化为对这个链表的管理。
打开文件的本质就是,程序执行open系统调用将文件打开,进程为了知道自己打开了哪些文件,在task_struct中会有一个struct file_struct *file的指针指向,一个struct file_struct的结构体,这个结构体中存在一个 struct file*的数组,fd就是这个数组的下标,我们通过fd就能找到对应的 struct file。
打开文件流程
首先就要为文件创建一个struct file ,将创建好的struct file链入链表中,然后放到struct file *fd array[],返回文件在数组中的下标。
fd的本质就是数组下标