当前位置: 首页 > news >正文

什么是文件描述符以及重定向的本质和软硬链接(Linux)

目录

    • 1 什么是文件?什么是文件操作?
      • 认识系统接口open
    • 什么是文件描述符
    • 认识Linux底层进程如何打开的文件映射关系
    • 重定向的本质
    • 理解软硬链接
    • 扩展问题

1 什么是文件?什么是文件操作?

文件 = 文件内容 + 文件属性(文件属性也是数据,即使你创建一个空文件,也要占据空间)
文件操作 = 文件内容操作 + 文件属性操作(有可能,在操作文件的过程中,既改变内容,又改变属性)
不管是学习语言还是学习操作系统,IO流是我们学习过程中不可获取的一个阶段,在这一部分我们会学习打开文件、读写文件等操作。
那所谓的“打开文件”,究竟是在干什么呢?其实就是将文件的属性或内容加载到内容中。
我相信大多数人的入门语言都是c语言,那我们就以c语言的文件操作进行举例;
如何理解printf?为什么调用printf就能往显示屏中打印内容呢?

其实printf是封装了系统的接口,然后由系统接口调用显示屏的驱动方法,然后进行打印

其实不管是C语言也好,Java也好,其他语言也罢,大多数的文件操作都是封装了系统接口。
封装的原因

  1. 原生系统接口使用成本比较高
  2. 语言不具备跨平台性(每个操作系统的接口可能不一样,写的代码可能只能在一个平台上跑)

封装是如何解决跨平台的问题的呢?

以c/c++方式举例:穷举所有底层接口 + 条件编译

在Linux系统调用接口中,我们打开文件使用open、关闭文件close、写入write、读取read。那这些接口和C中库函数接口有什么联系呢?我们可以这样理解:C中调用得这些库函数底层一定封装了系统调用接口,可以认为fopen底层调用open,fclose底层调用close,fread底层调用read,fwrite底层调用write。我们在windows中打开文件,windows底层也有一套自己的windows相关的api系统接口,当我们在windows使用C的库函数时,C调用的就是windows下的系统接口。这样在语言层面上就实现了跨平台性。
在这里插入图片描述

认识系统接口open

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>​
int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);

pathname: 要打开或创建的目标文件

flags: 打开文件时,可以传入多个参数选项,用下面的一个或者多个常量进行“或”运算,构成flags。

O_RDONLY: 只读打开

O_WRONLY: 只写打开

O_RDWR : 读,写打开

这三个常量,必须指定一个且只能指定一个

O_CREAT : 若文件不存在,则创建它。需要使用mode选项,来指明新文件的访问权限

O_APPEND: 追加写
返回值:

成功:新打开的文件描述符

失败:-1

int main()
{umask(0);int fda = open("loga.txt",O_WRONLY | O_CREAT | O_TRUNC,0666);int fdb = open("logb.txt",O_WRONLY | O_CREAT | O_TRUNC,0666);printf("fda:%d\n",fda);printf("fdb:%d\n",fdb);close(fda);close(fdb);return 0;
}

运行结果:

fda:3
fdb:4

什么是文件描述符

OK,那前面描述怎么多,到底什么是文件描述符呢?其实系统接口open的返回值就是文件描述符。
Linux系统中,把一切都看做是文件,当进程打开现有文件或创建新文件时,OS向进程返回一个文件描述符,文件描述符就是OS为了高效管理已被打开的文件所创建的索引,用来指向被打开的文件,基本上所有执行I/O操作的系统调用都会通过文件描述符。简单来说,文件描述符可以唯一标识一个新打开的文件;类似学号,身份证号可以唯一标识一个人。
OK,引出概念后,我们来解决下面几个问题
上面那个例子中,为什么运行结果是3,4;或者说为什么是从3开始?

因为操作系统默认已经打开0,1,2号文件
0表示:标准输入,键盘
1表示:标准输出,显示器
2表示:标准错误,显示器

认识Linux底层进程如何打开的文件映射关系

** 为什么文件描述符是像0,1,2,3,4,5…,你见过什么样的数据,是这样子的?**

当然是数组的下标就是这样子的啦

首先在一个进程可以打开多个文件(就像我们写代码可以打开多个文件一样),那这么多文件,我们的OS要怎么管理呢?
一个文件被打开,在内核中,要创建该打开的文件的内核数据结构叫做struct file

struct file
{//包含了我想看到的文件大部分内容+属性struct file *next;struct file *prev;
}

再讲这个结构体file用类似链表的数据结构给串起来,所以对被打开的文件的管理,转化为对链表的增删改查
** 那进程如何和打开的文件建立映射关系呢?**
看下图
在这里插入图片描述
首先task_struct(进程控制块PCB)里面有一个字段是struct files_struct* files;files_struct里面有一个文件描述符表,其实就是一个array[]数组,里面存着结构体file的地址;当我们用户要打开一个文件时,先给你创建struct file这个结构体,初始化file内部属性还有函数指针指向的对应的方法,并且在当前进程的文件描述符表里分配一个没有被使用的下标,将新文件的地址(也就是结构体file的地址)给文件描述符表;然后会将这个新文件对应的文件描述符表的下标返回给用户,后面用户在调用read,write,一定传入了对应的文件描述符(fd),根据这个文件描述符就能找到对应的文件,对它做相应的操作。
那肯定有人问了,0,1,2 对应stdin,stdout,stderr 对应 键盘,显示器,显示器(这些都是硬件啊)也用你上面的struct file 来标识吗?

是的,在Linux下一下皆文件
在这里插入图片描述
在Linux下一切皆文件,结构体struct file里面有函数指针,指向的就是对应的IO方法(read,write),像磁盘啊,显示器啊,键盘啊,这些硬件,调用他们要调用对应设备的驱动方法,所以struct file的函数指针,指向这些对应设备的驱动方法。比如说标椎输出2号文件,结构体的函数指针就是指向显示器的驱动方法,将数据写到2号文件,也就是显示到显示屏上。

所以一切皆文件,举个例子,把显示屏看做文件,我们往显示屏打印数据,不就是往文件里写东西而已。

你可以验证一下上面的理论,先把标准输出1号文件关闭了,再打开log.txt文件,根据fd的分配规则,新的fd值一定是1;所以此时调用printf();本来printf是打印到1号文件,也就是显示屏;但是现在打印到log.txt文件里取了(当然这个过程也叫做重定向)
文件描述符的分配规则:从头遍历数组fd_array[],找到一个最小的,没有被使用的下标,分配给新的文件

int main()
{close(1);//根据fd的分配规则,新的fd值一定是1int fd = open("log.txt",O_WRONLY | O_CREAT | O_TRUNC,0666);if(fd < 0){perror("oppen");return 1;}//printf-》stdout->1->虽然不在指向对应的显示器了,但是已经指向了log.txt的底层struct file 对象//本来应该要往显示器打印,最终却变成了向指定文件打印 -> 重定向printf("fd:%d\n",fd);//为什么必须要fflush一下fflush(stdout);close(fd);
}

重定向的本质

修改文件描述符fd下标 对应的struct file * 的内容 (将其换成目标文件的地址)。
重定向具体操作

int dup2(int oldfd,int newfd);//duplicate重定向
int main()int fd = open("log.txt",O_WRONLY | O_CREAT | O_TRUNC,0666);
if(fd < 0)
{perror("open");return 0;
}
dup2(fd,1)>=0
//本来应该要往显示器打印,最终却变成了向指定文件打印 -> 重定向
fprintf(stdout,"打开文件:%d",fd);
fflush(stdout);
close(fd);
return 0;
}

在这里插入图片描述

理解软硬链接

在讲软硬链接之前,我们得先了解一下什么是inode。
我们刚才说的,打开的文件是内存级别的,实际上大量的文件还在磁盘上,这些文件和多,很杂,我们的文件系统就要对这些进行管理。
那么一个硬件(磁盘)怎么跟我们的OS产生联系呢?
把磁盘想象成为线性结构,当做500GB大小的数组,然后对磁盘的管理,转化为了对数组空间的管理。但是一次性管理500GB大小的数组不太可能,所以就对500GB的数组进行分区,一个区100GB,一个区还是太大,在对区进行分组;一个组10G;组内在细分成块,然后内核对这些块进行描述,比如有什么属性,属于哪个组;然后就转为对这些块的管理。
Linux 系统中就有一个名为 superblock 的 “硬盘地图”。 Linux 并不是把文件内容直接写入到 superblock 中,而是在里面记录着整个文件系统的信息。superblock里面就有一个叫inode的。
文件= 内容 + 属性——都是数据——都要存储

Linux采用的是将内容和属性数据分开存储的方案

内容一般放在(一块块)block中(4kb),属性数据一般放在inode中(inode说人话就是磁盘上的另一份空间,一般这份空间是128字节)

Linux 把每个文件的权限与属性记录在 inode("索引节点:index node ") 中,而且每个文件占用一个独立的 inode 表格,该表格的默认大小为 128 字节。

里面记录着如下信息 :

  • 文件的访问权限(read、write、execute)

  • 该文件的所有者与所属组(owner、group)

  • 该文件的大小(size)

  • 该文件的创建或内容修改时间(ctime)

  • 该文件的最后一次访问时间(atime)

  • 该文件的修改时间(mtime)

  • 文件的特殊权限(SUID、SGID、SBIT)

  • 该文件的真实数据地址(point)。

在 Linux 系统中 ,inode 号才是文件的唯一标识而非文件名。文件名只是为了方便人们的记忆和适用

那我现在知道了,inode就是文件的唯一标识,用来存储文件的属性的,那软硬链接到底是什么呢?

硬链接(hard link) : 可以将它理解为一个 “指向原始文件 inode 的指针”,系统不为它分配独立的 inode 和 文件。所以,硬链接文件与原始文件其实是同一个文件,只是名字不同。我们每添加一个硬链接,该文件的 innode 连接数就会增加 1 ; 而且只有当该文件的 inode 连接数为 0 时,才算彻底被将它删除。因此即便删除原始文件,依然可以通过硬链接文件来访问。需要注意的是,我们不能跨分区对文件进行链接。所以硬链接可以用来防止误删。
软链接(symbolic link) : 等同于 Windows 系统下的快捷方式。仅仅包括所含链接文件的路径名字。因此能链接目录,也能跨文件系统链接。但是,当删除原始文件后,链接文件也将失效。

软硬链接的区别:软链接是一个独立文件,有自己独立的inode和inode编号;硬链接,不是一个独立的文件,它和目标文件使用同一个inode

扩展问题

  1. 什么是硬链接数??

    此时的inode编号,不是就一个“指针”的概念吗?硬链接数本质就是给文件inode属性中的一个计数器count,标识有几个文件名和我的inode建立了映射关系。简而言之,就是有几个文件名,指向我的inode(文件本身)

  2. 既然软链接是一个独立的文件,那它的文件内容是什么呢??

    保存的是指向文件的所在路径

  3. 为什么创建普通文件,默认硬链接数是1;而创建目录,默认硬链接数是2呢??

    普通文件的文件名,本身就和自己的inode具有映射关系,所以是1;

    默认的空目录,有两个默认文件.和…,.表示当前目录,也指向这个目录,所以目录自己指向自己的inode,.也指向目录的inode,所以是2;而…指向的是上级目录的inode

相关文章:

什么是文件描述符以及重定向的本质和软硬链接(Linux)

目录 1 什么是文件&#xff1f;什么是文件操作&#xff1f;认识系统接口open 什么是文件描述符认识Linux底层进程如何打开的文件映射关系重定向的本质理解软硬链接扩展问题 1 什么是文件&#xff1f;什么是文件操作&#xff1f; 文件 文件内容 文件属性&#xff08;文件属性…...

LVM逻辑卷元数据丢失恢复案例 —— 筑梦之路

Lvm常见的故障主要是pv出现异常&#xff0c;有以下几种情况 一个是pv所在的磁盘发生了lvm的元数据损坏一个是系统无法识别到pv所在的磁盘一个是系统异常&#xff0c;断电等导致重启后盘符发生变化&#xff0c;也就是系统识别的磁盘uuid发生变化&#xff0c;但是wwid还是可以对应…...

Java技术规范概览

Java技术规范 目录概述需求&#xff1a; 设计思路实现思路分析1.Java JSR的部分2.JSR-000373.JSR-0000394.JSR-000337 参考资料和推荐阅读 Survive by day and develop by night. talk for import biz , show your perfect code,full busy&#xff0c;skip hardness,make a bet…...

【OpenMMLab AI实战营第二期】二十分钟入门OpenMMLab笔记

OpenMMlab 主页&#xff1a;openmmlab.com 开源地址&#xff1a;https://github.com/open-mmlab 学习视频地址&#xff1a;https://www.bilibili.com/video/BV1js4y1i72P/ 概述 开源成为人工智能行业发展引擎 时间轴 theano&#xff1a;2007 Caffe&#xff1a;2013 Ten…...

docker-compose单机容器集群编排

docker-compose dockerfile模板文件可以定义一个独立的应用容器&#xff0c;如果需要多个容器就需要服务编排。服务编排有很多技术方案 docker-compose开源的项目实现对容器集群的快速编排 docker-compose将所管理的容器分为三层&#xff0c;分别为工程&#xff0c;服务&#…...

CentOS7 安装Gitlab

1、安装依赖 sudo yum install -y curl openssh-server ca-certificates tzdata perl libsemanage-devel 2、安装邮件服务工具 sudo yum install -y postfix 3、配置GitLab 软件源镜像 curl -fsSL https://packages.gitlab.cn/repository/raw/scripts/setup.sh | /bin/bash …...

Mysql InnoDB的Buffer Pool

Buffer Pool 在MySQL服务器启动的时候就向操作系统申请了⼀⽚连续的内存&#xff0c;他们给这⽚内存起了个名&#xff0c;叫做Buffer Pool&#xff08;中⽂名 是缓冲池&#xff09;。 默认情况下Buffer Pool只有128M⼤⼩&#xff0c;最⼩值为5M&#xff0c;通过修改配置文件设…...

SMTP简单邮件传输协议(C/C++ 发送电子邮件)

SMTP是用于通过Internet发送电子邮件的协议。电子邮件客户端&#xff08;如Microsoft Outlook或macOS Mail应用程序&#xff09;使用SMTP连接到邮件服务器并发送电子邮件。邮件服务器还使用SMTP将邮件从一个邮件服务器交换到另一个。它不用于从服务器下载电子邮件&#xff1b;相…...

uploads靶场通关(1-11关)

Pass-01&#xff08;JS校验&#xff09; 看题目我们准备好我们的php脚本文件&#xff0c;命名为1.php 上传该php文件&#xff0c;发现上传失败 方法一&#xff1a;将浏览器的JavaScript禁用 然后就能上传了 方法二&#xff1a; 查看源码&#xff0c;发现只能上传以下形式的文…...

6.1黄金探底回升是否到顶,今日多空如何布局

近期有哪些消息面影响黄金走势&#xff1f;今日黄金多空该如何研判&#xff1f; ​黄金消息面解析&#xff1a;周三(5月31日)黄金期货价格攀升&#xff0c;美国国债收益率下降推动金价升至一周最高收盘位。美市尾盘&#xff0c;现货黄金收报1962.42美元/盎司&#xff0c;上升3…...

自定义ViewGroup实现流式布局

目录 1、View的绘制流程 2、自定义ViewGroup构造函数的作用 3、onMeasure 方法 3.1、View的度量方式 3.2、onMeasure方法参数的介绍 3.3、自定义ViewGroup onMeasure 方法的实现 4、onLayout方法 5、onDraw方法 6、自定义View的生命周期 7、自定义流式布局的实现 扩展&#xff…...

Git版本控制

目录 版本控制 概念 为什么需要版本控制&#xff1f; 常见的版本控制工具 Git 1、安装 2、了解基本的Linux命令 3、配置git 用户名和邮箱 4、git 工作模式 5、git 项目管理 6、git 分支 托管平台 远程仓库 Gitee 关联多个远程库 Git服务器 Git GUI 版本控制 概…...

若依之权限处理

若依之权限处理 若依前后端不分离版本使用的是shiro进行权限控制&#xff0c;本文主要是对shiro在若依中的使用进行分析。 RBAC权限模型 RBAC是指基于角色的访问控制。其基本思想是&#xff0c;对系统的各种权限不是直接授予具体的用户&#xff0c;而是在用户集合与权限集合…...

华为OD机试真题 Java 实现【矩阵最大值】【2023 B卷 100分】,附详细解题思路

一、题目描述 给定一个仅包含0和1的N*N的二维矩阵,请计算二维矩阵的最大值。 计算规则如下: 1、每行元素按下标顺序组成一个二进制数(下标越大越排在低位),二进制数的值就是该行的值。矩阵各行值之和为矩阵的值。 2、允许通过向左或向右整体循环移动每行元素来改变各元…...

ModuleNotFoundError: No module named ‘transformers_modules.chatglm-6b_v1‘的解决方案

大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…...

MMPretrain代码课

安装注意事项 训练时需要基于算法库源码进行开发&#xff0c;所以需要git clone mmpretrain仓库。如果只调用&#xff0c;则pip install 即可。 from mmpretrain import get_model, list_models,inference_model分别用于模型的获取、例举、推理 此时还没加载预训练权重 tor…...

Selenium自动化程序被检测为爬虫,怎么屏蔽和绕过

Selenium 操作被屏蔽 使用selenium自动化网页时&#xff0c;有一定的概率会被目标网站识别&#xff0c;一旦被检测到&#xff0c;目标网站会拦截该客户端做出的网页操作。 比如淘宝和大众点评的登录页&#xff0c;当手工打开浏览器&#xff0c;输入用户名和密码时&#xff0c…...

Nvidia Jetson Orin:开发技巧

Jetson PXXX定义 P2180 -> Jetson TX1 P3310 -> Jetson TX2 P3489 -> Jetson TX2i P3448 -> Jetson Nano devkit P3448-0020 -> Jetson Nano production module P2888 -> Jetson Xavier P2888-0060 -> Jetson Xavier-8GB P3701 -> Jetson AGX Orin D…...

为什么需要 git 和 相关的小知识

为什么需要git和相关的小知识 先看一个实际需求&#xff0c;引出Git 问题: 公司五一活动计划 ● 先说一个最简单的情况&#xff0c;比如你做了公司五一活动计划书(如图) 解决方案: 版本管理工具(Git) 一句话: Git 是目前最流行的分布式版本控制软件 Git 是怎么来的? Git…...

(详解)vue中实现主题切换的三种方式

目录 一、背景 二、实现思路 方法1&#xff1a;定义全局的CSS变量 方法2&#xff1a;切换已定义好的css文件 方法3&#xff1a;切换顶级CSS类名 (需使用css处理器,如sass、less等) 一、背景 在我们开发中我们会遇到像是需要切换程序风格、主题切换啦这种应用场景。 参考大佬…...

MongoDB学习和应用(高效的非关系型数据库)

一丶 MongoDB简介 对于社交类软件的功能&#xff0c;我们需要对它的功能特点进行分析&#xff1a; 数据量会随着用户数增大而增大读多写少价值较低非好友看不到其动态信息地理位置的查询… 针对以上特点进行分析各大存储工具&#xff1a; mysql&#xff1a;关系型数据库&am…...

【Redis技术进阶之路】「原理分析系列开篇」分析客户端和服务端网络诵信交互实现(服务端执行命令请求的过程 - 初始化服务器)

服务端执行命令请求的过程 【专栏简介】【技术大纲】【专栏目标】【目标人群】1. Redis爱好者与社区成员2. 后端开发和系统架构师3. 计算机专业的本科生及研究生 初始化服务器1. 初始化服务器状态结构初始化RedisServer变量 2. 加载相关系统配置和用户配置参数定制化配置参数案…...

Fabric V2.5 通用溯源系统——增加图片上传与下载功能

fabric-trace项目在发布一年后,部署量已突破1000次,为支持更多场景,现新增支持图片信息上链,本文对图片上传、下载功能代码进行梳理,包含智能合约、后端、前端部分。 一、智能合约修改 为了增加图片信息上链溯源,需要对底层数据结构进行修改,在此对智能合约中的农产品数…...

为什么要创建 Vue 实例

核心原因:Vue 需要一个「控制中心」来驱动整个应用 你可以把 Vue 实例想象成你应用的**「大脑」或「引擎」。它负责协调模板、数据、逻辑和行为,将它们变成一个活的、可交互的应用**。没有这个实例,你的代码只是一堆静态的 HTML、JavaScript 变量和函数,无法「活」起来。 …...

系统掌握PyTorch:图解张量、Autograd、DataLoader、nn.Module与实战模型

本文较长&#xff0c;建议点赞收藏&#xff0c;以免遗失。更多AI大模型应用开发学习视频及资料&#xff0c;尽在聚客AI学院。 本文通过代码驱动的方式&#xff0c;系统讲解PyTorch核心概念和实战技巧&#xff0c;涵盖张量操作、自动微分、数据加载、模型构建和训练全流程&#…...

[论文阅读]TrustRAG: Enhancing Robustness and Trustworthiness in RAG

TrustRAG: Enhancing Robustness and Trustworthiness in RAG [2501.00879] TrustRAG: Enhancing Robustness and Trustworthiness in Retrieval-Augmented Generation 代码&#xff1a;HuichiZhou/TrustRAG: Code for "TrustRAG: Enhancing Robustness and Trustworthin…...

macOS 终端智能代理检测

&#x1f9e0; 终端智能代理检测&#xff1a;自动判断是否需要设置代理访问 GitHub 在开发中&#xff0c;使用 GitHub 是非常常见的需求。但有时候我们会发现某些命令失败、插件无法更新&#xff0c;例如&#xff1a; fatal: unable to access https://github.com/ohmyzsh/oh…...

高防服务器价格高原因分析

高防服务器的价格较高&#xff0c;主要是由于其特殊的防御机制、硬件配置、运营维护等多方面的综合成本。以下从技术、资源和服务三个维度详细解析高防服务器昂贵的原因&#xff1a; 一、硬件与技术投入 大带宽需求 DDoS攻击通过占用大量带宽资源瘫痪目标服务器&#xff0c;因此…...

Qwen系列之Qwen3解读:最强开源模型的细节拆解

文章目录 1.1分钟快览2.模型架构2.1.Dense模型2.2.MoE模型 3.预训练阶段3.1.数据3.2.训练3.3.评估 4.后训练阶段S1: 长链思维冷启动S2: 推理强化学习S3: 思考模式融合S4: 通用强化学习 5.全家桶中的小模型训练评估评估数据集评估细节评估效果弱智评估和民间Arena 分析展望 如果…...

接口 RESTful 中的超媒体:REST 架构的灵魂驱动

在 RESTful 架构中&#xff0c;** 超媒体&#xff08;Hypermedia&#xff09;** 是一个核心概念&#xff0c;它体现了 REST 的 “表述性状态转移&#xff08;Representational State Transfer&#xff09;” 的本质&#xff0c;也是区分 “真 RESTful API” 与 “伪 RESTful AP…...