序言:
前面在Linux 基础文件IO操作-CSDN博客这篇博客里说了很多函数无论是在语言层还是在系统调用的方面。在调用系统调用open的时候会返回一个整型,在write传参的时候第一个参数是一个叫fd的东西,这个是什么东西?这篇博客会详细解释这个问题。
Ⅰ、文件描述符
什么是文件描述符?当调用open时成功就会返回一个整数这个就是文件描述符(file descriptor
)
一、C语言FILE和文件描述符的关系
在语言层我们并没有看见过文件描述符,我们在C语言中经常用的是文件指针,好像文件指针和文件描述符在一些功能上是相识的,他们之间有什么关系吗?
在C语言库中FILE是一个结构体,它的里边就包含了文件描述符,也就是说FILE是对fd的一层封装。下面我们来看一段代码来证明这一点:
在C语言层对系统调用做封装,用来使用更加方便和提升代码的可移植性。
下面我们再来看一段代码:
1 #include<stdio.h>2 #include<string.h>3 #include<sys/stat.h>4 #include<fcntl.h>5 #include<sys/types.h> 6 7 8 int main()9 {10 int fd1 = open("log1.txt",O_WRONLY|O_CREAT|O_TRUNC);11 int fd2 = open("log2.txt",O_WRONLY|O_CREAT|O_TRUNC);12 int fd3 = open("log3.txt",O_WRONLY|O_CREAT|O_TRUNC);13 int fd4 = open("log4.txt",O_WRONLY|O_CREAT|O_TRUNC);14 15 printf("fd1 = %d\n",fd1);16 printf("fd2 = %d\n",fd2);17 printf("fd3 = %d\n",fd3);18 printf("fd4 = %d\n",fd4);19 return 0;20 }
在这里我们会很奇怪为什么我们打开的文件的文件描述符是从3开始而不是从0。当我们的代码开始运行的时候有三个文件流会默认打开,在C语言中叫stdin,stdout, stderr ,这三个文件流占据着0 ,1 ,2 下面我们来证明一下:
1 #include<stdio.h>2 #include<string.h>3 #include<sys/stat.h>4 #include<fcntl.h>5 #include<sys/types.h>6 7 8 int main()9 {10 FILE* fd = fopen("log.txt","w");11 12 printf("stdin = %d\n", stdin->_fileno ); 13 printf("stdout = %d\n", stdout->_fileno );14 printf("stderr = %d\n", stderr->_fileno );15 printf("log.txt = %d\n", fd->_fileno );16 17 18 fclose(fd);19 return 0;20 }
二、为什么要有文件操作符?
上一个博客我们说到我们要对文件进行管理采用 “先组织,再管理” 的思想所以有了struct_file组织各种文件的各种信息,如何去管理这些结构体呢?
再task_struct中会有一个指针指向指针数组,这些指针数组中放着各个struct_file的指针,这个指针数组就叫做文件描述表,数组的下标就是文件描述符,所以文件描述符就是数组的下标,操作系统通过这些文件描述符就可以去管理文件。
三、文件描述符的分配规则
当一个文件打开的时候就会把它的struct_file指针按照最小且没有被使用的地址存放,这块地址的下标作为这个文件的fd返回给用户。
1 #include<stdio.h>2 #include<string.h>3 #include<sys/stat.h>4 #include<fcntl.h>5 #include<sys/types.h>6 7 8 int main()9 {10 fclose(stdin);11 FILE* fd = fopen("log.txt","w");12 printf("log.txt = %d\n", fd->_fileno ); 13 printf("stdout = %d\n", stdout->_fileno );14 printf("stderr = %d\n", stderr->_fileno );15 16 17 fclose(fd);18 return 0;19 }
Ⅱ、重定向操作
一、重定向的本质
在linux中可以通过一些指令“ > ,>> , <”实现重定向操作。我们如何去实现重定向换句话来说重定向的本质是什么?我们在上面看见C语言中的stdin,stdout,stderr 的文件操作符分别是0,1,2,如果我们打开一个新的文件那么它的文件描述符就是 3 ,如果我们能将files_struct array[3]里的地址复制一份给files_struct array[1]里,那么也就相当于文件描述符为1指向的是我们打开的是我们打开的文件,怎么去改变这两个值呢?我们可以用系统调用dup2。
参数中的oldfd是要复制的地址的fd,而newfd是被复制地址的fd。按照我们上面说的例子那么oldfd是 3 我们打开的文件,而newfd是 fd = 1的这个文件。知道这个系统调用了以后我们可以做一个实验。
下面看一段代码:
1 #include<stdio.h>2 #include<string.h>3 #include<sys/stat.h>4 #include<fcntl.h>5 #include<sys/types.h>6 #include<unistd.h>7 8 int main()9 {10 int fd = open("log.txt",O_WRONLY|O_CREAT|O_TRUNC);11 dup2(fd,1);12 close(fd);13 printf("hello dup2\n"); 14 return 0;15 }
为什么我们printf没有向显示器上打而是向我们的文件里打呢?我们知道stdin,stdout,stderr分别是键盘文件,显示器文件,显示器文件,他们是固定的fd,在C语言在分装的函数比如printf,scanf在函数里封装了fd,所以他们的fd是固定的,那么我们通过更改fd = 1里的指针我们就可以实现输出重定向和追加重定向,更改fd = 0里的指针可以实现输入重定向。综上所述重定向的本质就是对文件描述符表对下标 0,1的改变。
=========================================================================
本篇关于Linux的文件理解与操作的介绍就暂告段落啦,希望能对大家的学习产生帮助,欢迎各位佬前来支持纠正!!!