利用open函数打开一个文件,并验证下是否能无限次打开文件
//openfile.c
#include <stdio.h> //C语言标准IO头文件,如调用printf()函数
#include <sys/types.h> //调用open()函数所需的头文件
#include <sys/stat.h>
#include <fcntl.h>
int main()
{
int fd; //定义一个变量fd,存放文件描述符
int i=1; //定义一个变量i,用来记录打开文件的次数
while(1)
{
fd = open("home/chenhai/test/main.c",O_RDWR); //打开main.c文件,以读写方式打开;在while循环中,连续的打开该文件
if(fd == -1)
{
printf("fail to open the file\n"); //如果文件描述符的值为-1,则打开文件失败
break;
}
else
{
printf("fd=%d,",fd);
printf("open main.c success %d\n",i++);
}
}
}
编译openfile.c程序并执行,按照程序逻辑,只要变量fd的值不为-1,就会陷入死循环一直打印
chenhai@linux:~/test$ gcc openfile.c -o demo
chenhai@linux:~/test$ ./demo
执行结果如下,可以看到,程序打印了1021次之后便退出了while循环,可见不能无限次打开文件main.c
通过Linux系统上的man手册,查看open函数的原型
chenhai@linux:~/test$ man 2 open //open函数属于内核提供的功能函数,所以在man手册的第2页
man手册是一个很好用的帮助文档,它分成9页:
页数 | 内容 |
---|---|
1 | Executable programs or shell commands 可执行程序或shell命令 |
2 | System calls (functions provided by the kernel) 系统调用(内核提供的功能) |
3 | Library calls (functions within program libraries) 库调用(程序库中的函数) |
4 | Special files (usually found in /dev) 个特殊文件(通常位于/ dev中) |
5 | File formats and conventions eg /etc/passwd 文件格式和约定,例如/ etc / passwd |
6 | Games |
7 | Miscellaneous (including macro packages and conventions), e.g. man(7), groff(7) 杂项(包括宏包和惯例) |
8 | System administration commands (usually only for root) 系统管理命令(通常仅用于root) |
9 | Kernel routines [Non standard] 内核例程[非标准] |
截取man手册中的open函数部分介绍进行分析,对于系统提供的IO接口函数,我们不用去深究它的实现原理,我们只要使用它就好,可以看到该函数open的返回值类型是int,参数有两个,char型的指针*pathname指向的是需要打开的文件路径名,int型的变量flags是打开文件的操作权限请求
对man手册中关于open()函数的接口规范,总结如下表
那么上面的程序运行结果中,fd的值是从3开始的,前面的0 1 2去哪了呢?我们都知道,在Linux系统中有句话,“一切皆文件”,我们则可以使用系统IO接口去访问Linux系统中的所有文件,当申请打开一个文件的时候,系统会分配一个文件描述符给你,但是这个分配是有限度的,通过实验我们可以知道,打开文件的最大值为1023,其实就相当于去医院看病拿号一样,把医院当成一个系统,你去申请了排队看病,就分配了一个号码给你,当天的号码数量有限,分完即止,那每个人拿着这个号码(文件描述符),就可以去访问对应的医生(文件)了;之所以从3开始分配啊,是因为前面0-2都已经分配好了,0对应着标准输入设备文件(键盘),1对应着标准输出设备(屏幕),2标准出错设备(系统错误信息),所以啊这前面的三个号不能给你,你要申请只能从3开始
总结
每一个被打开的文件(键盘,显示器都是文件)都会有一个非负的描述符来对应他们;一个文件可以被重复打开多次,但不能无限次打开;每打开一次也都会有一个描述符对应,并且可以有不同的模式(文件操作权限);