什么是文件描述符
- C语言的文件接口
- 文件的系统调用
- 什么是文件描述符,文件描述符为什么是int类型?
- 为什么新打开的文件的文件描述符不是从0开始?
文件描述符 fd (file descriptor)
C语言的文件接口
当时学习C语言的时候,学习了文件接口
具体可以查看之前的文章: 链接:C语言的文件操作 http://t.csdnimg.cn/H6oAH
举例:
#include<stdio.h>
int main()
{
//打开文件
FILE* pf = fopen("test.txt", "w"); //以只写的方式打开/创建文本文件
if (pf == NULL) //判定是否打开成功,当打开文件失败时,fopen函数会返回空指针
{
perror("fopen");
return 1;
}
// 写文件
//关闭文件
fclose(pf);
pf = NULL; //用完指针后置空
return 0;
}
而文件的打开方式及意义是重点:
文件使用方式 | 含义 | 如果指定文件不存在 |
---|---|---|
“r”(只读) | 为了输入数据,打开一个已经存在的文本文件 | 出错 |
“w”(只写) | 为了输出数据,打开一个文本文件 | 建立一个新的文件 |
“a”(追加) | 向文本文件尾添加数据 | 建立一个新的文件 |
“rb”(只读) | 为了输入数据,打开一个二进制文件 | 出错 |
“wb”(只写) | 为了输出数据,打开一个二进制文件 | 建立一个新的文件 |
“ab”(追加) | 向一个二进制文件尾添加数据 | 出错 |
“r+”(读写) | 为了读和写,打开一个文本文件 | 出错 |
“w+”(读写) | 为了读和写,建立一个新的文件 | 建立一个新的文件 |
“a+”(读写) | 为了读和写,在文件尾进行读写 | 建立一个新的文件 |
“rb+”(读写) | 为了读和写,打开一个二进制文件 | 出错 |
“wb+”(读写) | 为了读和写,建立一个新的二进制文件 | 建立一个新的文件 |
“ab+”(读写) | 打开一个二进制文件,在文件尾进行读写 | 建立一个新的文件 |
但是上面的接口,只是单纯的C语言写出来对文件进行调用和操作的
而对文件(即磁盘)进行操作的权力实际上只有操作系统,实际上C语言是封装了操作系统的系统调用
FILE 是一个C语言提供的结构体类型
文件的系统调用
上面讲到,C语言的文件操作函数实际上是封装了系统调用,实际上调用的就是open函数;
参数解析:
pathname: 要打开或创建的目标文件
flags: 打开文件时,可以传入多个参数选项,用下面的一个或者多个常量进行“或”运算,构成flags。
参数:
O_RDONLY: 只读打开
O_WRONLY: 只写打开
O_RDWR : 读,写打开
这三个常量,必须指定一个且只能指定一个
O_CREAT : 若文件不存在,则创建它。需要使用mode选项,来指明新文件的访问权限
O_APPEND: 追加写
返回值:
打开成功,返回对应的文件描述符
打开失败,返回 -1
可以看到,open函数的返回值是一个int类型,这个返回值就是操作系统想要得到的文件描述符
什么是文件描述符,文件描述符为什么是int类型?
在操作系统中,每个进程都可能会打开多个文件,那么操作系统就需要对这些多个文件进行管理,因此操作系统会在这个进程的PCB中创建一个专门管理文件的结构体struct files_struct *files,而这个结构体中又包含了一个结构体指针数组,这个数组的下标就是文件描述符
如图:
而我们所知道的文件描述符,实际上就是对文件管理pcb中文件描述符结构体指针数组这个数组的下标,让操作系统明白我们调用的是这多个文件中的哪一个文件
为什么新打开的文件的文件描述符不是从0开始?
因为Linux下一切皆文件,因此每当创建一个进程的时候,操作系统默认会打开三个文件:
- 标准输入(stdin) 键盘 (描述文件符 0)
- 标准输出(stdout) 显示器 (描述文件符 1)
- 标准错误(stderr) 显示器 (描述文件符 2)
这三个文件占用了文件描述符数组的前三位,因此每当我们创建一个进程后,打开的每一个文件的文件描述符都是从3开始的
因此,各种语言 如C/C++,Java,python 等等,对文件的操作基本都是对系统调用函数open 进行的封装,因为操作系统与语言无关,无论什么语言,想要在操作系统下跑起来,那就得遵守这个操作系统的规矩,而文件调用这里的规矩,就是去封装open这个系统调用!