当前位置:   article > 正文

Linux文件描述符fd的理解_linux fd

linux fd

Linux文件描述符fd的理解

在这里插入图片描述

1.引言

​ 文件描述符是一种用于标识文件打开的非负整数,是系统打开文件接口open()等函数的返回值。本质是进程中文件结构体file_struct的数组下标。每次打开一个文件都会有一个对应的fd文件描述符。通过对文件描述符的操作可以对文件进行打开、读取、写入、关闭等功能。

​ 文件描述符下标0,1,2分别用来表示标准输入(stdin)、标准输出(stdout)、标准错误(stderr)。这前三个0,1,2描述符都是在进程打开时,被文件系统默认占用的三个描述符。根据文件描述符分配规则:把最小未使用的fd下标给用户使用,后面用户的文件获取到的默认都是从3往后走。

**不过这种系统默认的占用可以被用户手动关闭后由用户自己的文件来占用的。**占用的位置不同呈现出来的效果也不同。这个我们在后面会提到。

标准输入:即输入的内容,通常默认由键盘等外设来读取。

标准输出:例如printf、cout等函数就是向标准输出中打印信息的。

标准错误:例如cerr、perror等错误函数就是向标准错误中打印信息的。

在这里插入图片描述

2.具体分析

2.1 用户fd下标默认从3开始

​ 先看下面一段C代码,我们来打印一下用户文件的描述符。

​ open()函数中,前面是自拟文件名,O_WRONLY是只读权限选项,O_CREAT是文件无则创建选项,O_TRUNC是文件截断选项,一般不用理会,后面0666是用户可读可写权限。

	int fd = open("myfd.txt",O_WRONLY | O_CREAT | O_TRUNC,0666);
    int fd2 = open("myfd.txt",O_WRONLY | O_CREAT | O_TRUNC,0666);
    int fd3 = open("myfd.txt",O_WRONLY | O_CREAT | O_TRUNC,0666);
    int fd4 = open("myfd.txt",O_WRONLY | O_CREAT | O_TRUNC,0666);
    int fd5 = open("myfd.txt",O_WRONLY | O_CREAT | O_TRUNC,0666);
		//打印相应的文件描述符fd
    printf("%d\n",fd);
    printf("%d\n",fd2);
    printf("%d\n",fd3);
    printf("%d\n",fd4);
    printf("%d\n",fd5);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

在这里插入图片描述

结果跟我们预料到的一样,0,1,2会被系统默认占用,用户文件的fd是默认从3往后走的


2.2 关闭系统占用后用户可以占用

好,我们现在来变动一下,在上述代码前加上**close(0)**关闭标准输出代码,结果会怎么样呢?

close(0);  //关闭标准输出
  • 1

在这里插入图片描述

根据上述文件描述符分配规则:把最小未使用的fd下标给用户使用当系统占用0被关闭后就留给用户使用了

在这里插入图片描述

2.2.1用户占用0号,则从用户文件中读数据

**那占用系统的标准输入0到底有什么意义呢?**我们再来看以下简单代码。

假设我的用户文本log.txt中只有123 456的内容。

以下代码会出现什么结果呢?

	close(0);
	int fd = open("log.txt",O_RDONLY,0666); //打开用户文本
	int a,b;
    scanf("%d %d",&a,&b);
    printf("a = %d,b = %d",a,b);
  • 1
  • 2
  • 3
  • 4
  • 5

结果如下:

在这里插入图片描述

关于这个结果我们好奇两个问题:

1.为什么还没等我scanf进行手动输入,就自动出了结果?

2.为什么a、b结果刚好是我log.txt文件中的内容?

原因:

这是因为我们上述代码关闭了系统默认占用的0号文件描述符,转而让用户文件占用了0号标准输入的位置,那么本该从scanf键盘读取的数据,改为了直接从文件读取数据!!

2.2.2用户占用1号,则实现重定向

刚才上面我们是让用户占用了0号标准输入描述符,现在我们来让用户占领1号标准输出描述符,看看会出现什么结果。

我们来看以下简单代码:

  		close(1);
    	int fd = open("log.txt",O_WRONLY | O_CREAT | O_TRUNC,0666);
    	printf("new u can see me now!\n");
  • 1
  • 2
  • 3

我们来执行以下看看结果:

在这里插入图片描述

奇怪! 执行之后有个printf函数应该向显示器打印语句的,但是却没有显示,那么没有向显示器打印,难道向别的位置打印了?

​ 我们再来看一下log.txt用户文本中:

在这里插入图片描述

吃惊的一幕发现了! 原本应该向显示器打印的内容,结果却打印到用户文本中了。

上述原因是: printf的原理是向标准输出1号打印信息,但是现在标准输出被关闭后,按照文件描述符分配原则,最小未被使用的1号被用户占用,那么printf()也就从向显示器打印信息改为了向用户文件打印信息。

在这里插入图片描述

是的! 这种将程序的输入或输出从默认位置(通常是终端)转移到其他位置或设备的技术,就是重定向。

2.3 dup2()重定向函数

重定向在实际生产过程中,被用到的机会还是很大的,那难道我们都要向上述关闭文件描述符的方法一样去使用吗?肯定不是的

在指令上,我们有:‘>’ 符号来简便重定向:

echo “hello world” > myfd.txt

在这里插入图片描述

在代码上,我们还有现成的dup2()函数来专门重定向:

在这里插入图片描述

dup2() 函数是一个系统调用,用于复制一个文件描述符,并将其指向另一个文件描述符所指向的文件或设备。它的原型如下:

int dup2(int oldfd, int newfd);

其中,oldfd 是要复制的文件描述符,newfd 是要指向的新文件描述符。

值得弄混淆的是:是将newfd重定向到oldfd中!


使用方法如下:

int fd = open("file.txt", O_RDWR);
int newfd = 5;  // 指定新的文件描述符
int ret = dup2(fd, newfd);
if (ret == -1) {
    // 错误处理
}
close(fd);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

需要注意的是,如果 newfd 已经打开了一个文件,那么该文件将被关闭并被替换为与 oldfd 相同的文件。如果 newfd 等于 oldfd,那么 dup2() 函数将不起作用,并返回 newfd。

3.总结

​ 最后总结几点规则

​ 1.文件描述符分配规则:把最小未使用的fd下标给用户使用。系统默认占用的关闭后也可占用

​ 2.**close()是系统调用接口,fclose()是C库函数。**fclose(stdin) == close(0);

​ 3.printf/cout 默认往标准输出1号文件描述符去打印的,cerr/perror同理,默认往标准错误2号文件描述符去打印的

​ 4.重定向的原理是:更改文件描述符fd,从而更改打印方向等。

​ 5.文件描述符fd本质是文件结构体数组下标。

​ 6.任何文件的前三号文件描述符0、1、2都是先默认被系统占用的。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/繁依Fanyi0/article/detail/721823
推荐阅读
相关标签
  

闽ICP备14008679号