目录
文件描述符
系统调用 open
为什么fd从3开始呢?
为什么是0,1,2,3...呢?
文件描述符分配规则
系统调用 close
系统调用 wirte
系统调用 read
文件描述符
在了解文件描述符之前,先了解关于操作文件的系统调用,C语言中的fwrite,fread等等对文件操作的函数不是系统调用,而是C语言对系统调用做的封装。
语言为什么对系统调用封装?
1.原生的系统接口,使用成本较高
2.不同系统系统接口不同,直接使用接口,语言不具备跨平台性
什么是跨平台性?
C语言穷举了所有OS系统的底层接口并进行条件编译去封装不同系统的系统调用,就让C语言写的程序在不同的OS下都能正常编译运行,就称C语言具有跨平台性。
系统调用 open
参数含义是:open(文件路径,打开方式,权限)
参数flag表示打开方式,用宏传递,有O_RDONLY只读,O_WRONLY只写,O_RDWR读写三者取一,可加O_CREAT,O_TRUNC等,添加参数时用 | 的方式,因为系统调用传递标记位,是位图结构来传递的,简单来说不同的比特位具有不同的含义,或上不同的宏就是给不同位标记。
参数mode表示权限传递八进制数字,比如0666就可以了,如果要防止系统默认权限掩码影响,可以先调用umask函数修改权限。
返回值:返回文件描述符,-1返回值代表错误
使用示例:
输出:
为什么fd从3开始呢?
因为0表示标准输入,1表示标准输出,2表示标准错误,当程序运行的时候,这三个文件已经被默认打开了,在C语言封装的结构体FILE中就有fileno成员就是表示文件描述符,比如下面代码输出:
为什么是0,1,2,3...呢?
内核中用struct file结构体描述被打开的 文件(被打开的文件在内存中),进程pcb中有struct files_struct *files指针,指向描述进程打开文件的结构体,结构体中有struct file*fd_array[]指针数组存放指针,指针指向内核打开的文件,内核打开的文件被OS用链表维护起来。
文件描述符分配规则
从头遍历fd_array[]数组,找到一个最小的没有被使用的下标,比如关闭1号文件,打开新文件的文件描述符是1,往1文件中打印则会往新文件打印,先写到了缓冲区(语言级别)中 ,加\n也不刷新,因为写到磁盘的刷新策略是全缓冲,所以程序运行中除非强制刷新否则不刷新,程序退出会刷新。
使用系统调用dup2也可以完成上述的重定向操作,拷贝文件描述符对应的内容(本质是拷贝内核文件结构体指针),最终指向同一个文件
注意:int dup2(int oldfd,int newfd) ,是将oldfd的内容拷贝到newfd,最后只剩oldfd,往newfd输出就会输出到oldfd文件,这就是输出重定向。
系统调用 close
函数原型:int close(int fd),参数就是要关闭的文件的文件描述符
注意,这里的关闭是进程关闭了文件,管理文件结构体的释放是OS的工作,文件内核结构中用计数器存储文件被打开的次数,进程关闭只需将指针数组对应下标内容改成NULL,并将计数器--即可。
系统调用 wirte
从buf中写入fd文件中,写入count字节,返回值类型是ssize_t表示有符号整数,写入失败就返回-1,写入成功就返回写入的个数。
系统调用 read
返回值
>0,返回读取个数
=0 表示读取到了EOF
<0 读取失败