Linux中的文件描述符

这篇具有很好参考价值的文章主要介绍了Linux中的文件描述符。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1. 认识文件描述符

Linux中的文件描述符

文件描述符的概念:在Linux中,文件描述符是内核为了高效的管理已经被打开的文件所创建的索引 ,它是一个非负整数,用于指代被打开的文件,所有执行I/O操作的系统调用都是通过文件描述符完成的。文件描述符是一个简单的非负整数,用来表明每一个被进程打开的文件。
在Linux中,进程是通过文件描述符 (file descriptors 简称fd)来访问文件的,文件描述符实际上是一个整数。 在程序刚启动的时候,默认有三个文件描述符,分别是:0 (代表标准输入),1 (代表标准输出),2 (代表标准错误)。 我们可以通过open函数得到一个指定文件的文件描述符,如果出现错误则返回-1。open函数需要传入一个文件路径和操作模式,调用会返回一个整型的文件描述符。
Linux中的文件描述符
在Linux系统中,open函数主要作用就是打开和创建文件,可以根据参数来定制需要的文件的属性和用户权限等各种参数。flag参数相当于是宏,并且是可选的,用于设置打开文件的模式。flag参数的取值如下:

O_RDONLY: 只读模式
O_WRONLY: 只写模式
O_RDWR : 读写模式
O_NONBLOCK: 非阻塞模式
O_APPEND: 追加模式
O_CREAT: 创建并打开一个新文件
O_TRUNC: 打开一个文件并截断它的长度为零(必须有写权限)
O_EXCL: 如果指定的文件存在,返回错误

open的用法

接下来我们打印一些文件描述符,观察一下文件描述符的规律;

#include <stdio.h>    
#include <errno.h>    
#include <string.h>    
#include <unistd.h>    
#include <sys/types.h>    
#include <sys/stat.h>    
#include <fcntl.h>

int main()
{
    int fd1 = open("log.txt", O_CREAT | O_WRONLY | O_TRUNC, 0666);
    int fd2 = open("log.txt", O_CREAT | O_WRONLY | O_TRUNC, 0666);
    int fd3 = open("log.txt", O_CREAT | O_WRONLY | O_TRUNC, 0666);
    int fd4 = open("log.txt", O_CREAT | O_WRONLY | O_TRUNC, 0666);
    int fd5 = open("log.txt", O_CREAT | O_WRONLY | O_TRUNC, 0666);
    printf("fd1: %d\n", fd1);
    printf("fd2: %d\n", fd2);
    printf("fd3: %d\n", fd3);
    printf("fd4: %d\n", fd4);
    printf("fd5: %d\n", fd5);
    close(fd1);
    close(fd2);
    close(fd3);
    close(fd4);
    close(fd5);

    return 0;
}

可以看到是一串连续的整数,而0,1, 2是默认的文件描述符,分别是0 (代表标准输入),1 (代表标准输出),2 (代表标准错误),所以文件描述符(open对应的返回值)本质就是:数组下标。
Linux中的文件描述符
当我们打开一个文件,我们并没有创建数组,那么怎么会有上图的数组下标?

在Linux中,打开文件的过程涉及到进程、文件描述符、文件描述表、打开文件表、目录项、索引表之间的联系。当我们打开一个文件时,主要涉及了进程,文件描述符,文件描述表,打开文件表,目录项,索引表之间的联系。
具体来说,当我们打开一个文件时,操作系统会为该进程分配一个文件描述符(file descriptor),并将其存储在该进程的文件描述符表(file descriptor table)中。然后,操作系统会在打开文件表(open file table)中创建一个新的条目,并将该条目与该文件描述符相关联。此外,操作系统还会在目录项(directory entry)和索引表(inode table)中查找该文件,并将其加载到内存中。最后,操作系统会返回该文件描述符给应用程序,以便应用程序可以使用该文件描述符来访问该文件。

Linux中的文件描述符
打开一个文件,系统做了大致如下几件事,首先CPU会寻找对应的struct task_struct(也就是进程PCB);struct task_struct中有许多的struct file_struct *files指针,这些指针指向的就是不同的文件结构体,而struct file_struct结构体中就记录着文件描述符(操作系统方面,我们必须要访问fd(文件描述符),才能找到文件!);0、1、2对应的是三个默认的文件描述符,之后的文件描述符就是open返回的;磁盘将文件加载到内存,通过fd我们可以查找到内存中的文件,这些大致就是我们访问文件,操作系统的处理。
概念:PCB(Process Control Block)是进程控制块的缩写,是操作系统中最重要的记录型数据结构之一。PCB中记录了操作系统所需要的、用于描述进程情况及控制进程运行所需要的全部信息。

struct file结构体中,包含了文件权限,文件的大小,自己的缓冲区以及readp和writep等信息,这些信息都是以文件的方式存在的,外设通过驱动程序中的代码可以对文件进行读写。

Linux中所有内容都是以文件的形式保存和管理的。普通文件是文件,目录(Windows下称为文件夹)是文件,硬件设备(键盘、监视器、硬盘、打印机)是文件,所以说linux下一切皆文件。
查看文件描述符0, 1, 2,代码如下:

#include <stdio.h>    
#include <errno.h>    
#include <string.h>    
#include <unistd.h>    
#include <sys/types.h>    
#include <sys/stat.h>    
#include <fcntl.h>

int main()
{
    printf("%d\n", stdin->_fileno);
    printf("%d\n", stdout->_fileno);
    printf("%d\n",stderr->_fileno);
    File* fd = fopen("log.txt", w);
    printf("%d\n", fd->fileno);
 
    return 0;
}

Linux中的文件描述符

2. 更改默认的文件描述符

文件描述符的分配规则是什么?请看如下代码:

int main()
{
	//先关闭0,2,再进行打开文件
    close(0);
    close(2);
    int fd1 = open("log.txt", O_CREAT | O_WRONLY | O_TRUNC, 0666);
    int fd2 = open("log.txt", O_CREAT | O_WRONLY | O_TRUNC, 0666);
    int fd3 = open("log.txt", O_CREAT | O_WRONLY | O_TRUNC, 0666);
    int fd4 = open("log.txt", O_CREAT | O_WRONLY | O_TRUNC, 0666);
    int fd5 = open("log.txt", O_CREAT | O_WRONLY | O_TRUNC, 0666);
    printf("fd1: %d\n", fd1);
    printf("fd2: %d\n", fd2);
    printf("fd3: %d\n", fd3);
    printf("fd4: %d\n", fd4);
    printf("fd5: %d\n", fd5);
    close(fd1);
    close(fd2);
    close(fd3);
    close(fd4);
    close(fd5);
	return 0;
}

Linux中的文件描述符
在Linux中,每个进程都有一个独立的文件描述符表,该表是一个数组,每个元素都是一个指向file结构体的指针。当进程打开一个文件时,内核会为该进程分配一个新的文件描述符,并将其返回给进程。文件描述符分配规则是在file_struct数组中,找到当前没有被使用的最小的一个下标, 作为新的文件描述符。

2.1 输出重定向

#include <stdio.h>    
#include <errno.h>    
#include <string.h>    
#include <unistd.h>    
#include <sys/types.h>    
#include <sys/stat.h>    
#include <fcntl.h>

int main()
{
    close(1);
    int fd = open("log.txt", O_CREAT | O_WRONLY | O_TRUNC, 0666); //1
    printf("aaaaaaaaaaaa\n");
    printf("aaaaaaaaaaaa\n");
    printf("aaaaaaaaaaaa\n");
    //不用关掉fd :close(fd);

    return 0;
}

如上代码,先关掉默认描述符1(代表标准输出),所以关掉后printf函数就不会打印到显示器上;open后会返回一个文件描述符,根据文件描述符的规则:找到当前没有被使用的最小的一个下标,所以fd就是1;然后再打印字符串。
Linux中的文件描述符
程序运行后,可以看到,数据没有打印在显示器上,而是打印在log.txt文件中了,这就是输出重定向。重定向的原理:在上层无法感知的情况下,在OS内部,更改进程对应的文件描述符表中,特定下标的指向。

2.2 输入重定向

先在log.txt文件中写入1234 5678

#include <stdio.h>    
#include <errno.h>    
#include <string.h>    
#include <unistd.h>    
#include <sys/types.h>    
#include <sys/stat.h>    
#include <fcntl.h>

int main()
{
    close(0);
    int fd = open("log.txt", O_RDONLY);//0
    int a = 0, b = 0;
    scanf("%d %d",&a, &b);

    printf("a = %d, b = %d\n", a, b);
    return 0;
}

如上代码,先关掉默认描述符0(代表标准输入),open后会返回一个文件描述符,根据文件描述符的规则:找到当前没有被使用的最小的一个下标,所以fd就是0;然后再读取数据。
Linux中的文件描述符
可以看到数据不是从键盘上读取的,而是从log.txt文件中读取的,这就是输入重定向。

2.3 追加重定向

追加重定向也是向显示器或文件中打印,所以close(1)。

#include <stdio.h>    
#include <string.h>    
#include <unistd.h>    
#include <sys/types.h>    
#include <sys/stat.h>    
#include <fcntl.h>

int main()
{
    close(1);
    int fd = open("log.txt", O_CREAT | O_WRONLY | O_APPEND, 0666);
    printf("aaaaaaaaaaaa\n");
    printf("aaaaaaaaaaaa\n");

    return 0;
}

Linux中的文件描述符

3. dup2函数

将常规消息打印打log.txt,将异常消息打印到err.txt?由上面概念所示,我们需要close(1),然后open一下,再close(2),然后open一个文件就行。

#include <stdio.h>    
#include <string.h>    
#include <unistd.h>    
#include <sys/types.h>    
#include <sys/stat.h>    
#include <fcntl.h>

int main()
{
    close(1);
    open("log.txt", O_CREAT | O_WRONLY | O_APPEND, 0666);

    close(2);
    open("err.txt", O_CREAT | O_WRONLY | O_APPEND, 0666);
    //因为linux下一切皆文件,所以向显示器打印,本质就是向文件中写入
    printf("hello printf->stdout\n");
    printf("hello printf->stdout\n");
    fprintf(stdout, "hello fprintf->stdout\n");
    fprintf(stdout, "hello fprintf->stdout\n");
    
    fprintf(stderr, "hello fprintf->stderr\n");
    fprintf(stderr, "hello fprintf->stderr\n");
    
    return 0;
}

运行结果如预料一样,如下所示:
Linux中的文件描述符
如果我们需要将常规消息打印打log.txt,将异常消息打印到err.txt,那么我们要先关闭,再open,这样的工作就比较不方便,所以就有了dup。
Linux中的文件描述符
dup2()是Linux系统中的一个系统调用,它可以将一个文件描述符复制到另一个文件描述符。 dup2()函数的原型如下:int dup2(int oldfd, int newfd);。
dup2()函数的作用是将newfd指向oldfd指向的文件,如果newfd已经打开,则先关闭newfd,然后将newfd指向oldfd指向的文件。文章来源地址https://www.toymoban.com/news/detail-463138.html

#include <stdio.h>    
#include <string.h>    
#include <unistd.h>    
#include <sys/types.h>    
#include <sys/stat.h>    
#include <fcntl.h>

int main()
{
    int fd1 = open("log.txt", O_CREAT | O_WRONLY | O_APPEND, 0666);

    int fd2 = open("err.txt", O_CREAT | O_WRONLY | O_APPEND, 0666);
    
    dup2(fd1, 1);
    dup2(fd2, 2);
    //因为linux下一切皆文件,所以向显示器打印,本质就是向文件中写入
    printf("hello printf->stdout\n");
    printf("hello printf->stdout\n");
    fprintf(stdout, "hello fprintf->stdout\n");
    fprintf(stdout, "hello fprintf->stdout\n");
    
    fprintf(stderr, "hello fprintf->stderr\n");
    fprintf(stderr, "hello fprintf->stderr\n");
    
    return 0;
}

到了这里,关于Linux中的文件描述符的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 详解—[Linux 文件描述符]

    一、文件描述符的概念  文件描述符 是Linux系统中用于访问文件的一种机制,它是一个 非负整数 ,用于指代 被打开的文件 。 在Linux中,所有执行I/O操作的系统调用都是通过文件描述符完成的。 文件描述符是一个简单的非负整数,用来表明每一个被进程打开的文件。 在程序

    2024年02月04日
    浏览(43)
  • 【Linux】文件描述符 (上篇)

    本章开始,我们将进入Linux文件相关的学习与操作,从复习回顾C语言的文件操作接口,再从操作系统角度出发,学习系统调用接口。再了解虚拟文件系统,内核管理文件的数据结构。最后通过学习的操作文件的系统接口来模拟实现C语言的文件操作接口,最后对之前实现的sh

    2024年02月12日
    浏览(32)
  • 【Linux】文件描述符 - fd

    使用 man open 指令查看手册: open 函数具体使用哪个,和具体应用场景有关。如:目标文件不存在,需要 open 创建,则第三个参数表示创建文件的默认权限;否则使用两个参数的 open。 write read close lseek ,类比 C 文件相关接口。 操作文件,除了使用 C 语言的接口【Linux】回顾

    2024年03月23日
    浏览(33)
  • (20)Linux初始文件描述符

    前言:本章我们介绍 O_WRONLY, O_TRUNC, O_APPEND 和 O_RDONLY。之后我们开始讲解文件描述符。 C 语言在 w 模式打开文件时,文件内容是会被清空的,但是 O_WRONLY 好像并非如此? 代码演示: 当前我们的 log.txt 内有 5 行数据,现在我们执行下面的代码:  运行结果: 我们以前在 C 语

    2024年02月02日
    浏览(35)
  • Linux文件描述符和文件指针互转

    本文研究的主要是Linux中文件描述符fd与文件指针FILE*互相转换的相关内容,具体介绍如下。 1.文件描述符fd的定义: 文件描述符在形式上是一个非负整数。实际上,它是一个索引值,指向内核为每一个进程所维护的该进程打开文件的记录表。当程序打开一个现有文件或者创建一

    2024年02月08日
    浏览(30)
  • Linux - fd文件描述符和文件详解

                                                      ​​​​​​​             ​​​​​​​                                                   感谢各位 点赞 收藏 评论 三连支持                                                 本文

    2024年02月08日
    浏览(36)
  • [Linux]文件描述符(万字详解)

    在学习文件描述符前,首先要了解一下Linux系统常用的文件系统接口。 open函数 open函数有两个接口,三个参数的接口是在两个参数的接口的基础上添加了控制创建文件的权限功能,更适合写文件时使用 pathname参数 – 要打开的文件所在的路径 flags参数 – 打开文件的方式 mode参

    2024年02月10日
    浏览(33)
  • Linux文件描述符和打开文件之间的关系

    简介 文件描述符和打开的文件之间似乎呈现出一一对应的关系。然而,实际并非如此。多个文件描述符指向同一打开文件,这既有可能,也属必要。这些文件描述符可在相同或不同的进程中打开。 要理解具体情况如何,需要查看由内核维护的 3 个数据结构。 进程级的文件描

    2024年02月07日
    浏览(28)
  • 【Linux】基础 IO(文件描述符)-- 详解

    1、 文件的宏观理解 文件在哪呢? 从广义上理解,键盘、显示器、网卡、声卡、显卡、磁盘等几乎所有的外设都可以称之为文件,因为 “Linux 下,一切皆文件”。 从狭义上的理解, 文件在 磁盘(硬件) 上放着 ,只有操作系统才能真正的去访问磁盘。磁盘是一种永久存储介

    2024年03月24日
    浏览(36)
  • 【看表情包学Linux】文件描述符

       🤣  爆笑 教程  👉 《看表情包学Linux》👈   猛戳订阅     🔥 💭 写在前面: 在上一章中,我们已经把 fd 的基本原理搞清楚了。本章我们将开始探索 fd 的应用特征,探索 文件描述符的分配原则。讲解重定向,上一章是如何使用 fflush 把内容变出来的,介绍 dup2 函数,

    2023年04月15日
    浏览(30)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包