Linux文件描述符的分配机制与重定向实现:揭开“一切皆文件”的面纱
Linux系列
文章目录
- Linux系列
- 前言
- 一、Linux的标准流
- 二、文件描述符分配规则
- 三、文件重定向
- 四、Linux下一切皆文件
前言
上篇我们介绍了语言和系统层次的基础I/O文件操作,其涉及的知识有:C语言文件操作和系统调用接口两者的关系、文件描述符的概念、操作系统对文件的管理等。本篇我们将承接上一篇文章以继续深入探讨Linux中文件操作。
一、Linux的标准流
在上篇文章中我们遗留了一个问题:
文件描述符0(标准输入)对应键盘、1(标准输出)对应显示器、2(标准错误)对应显示器,为什么后两者都对应显示器,还要用不同的文件描述符标识?是如何实现的呢?今天我们就来回答这些问题。
1 #include<stdio.h>2 #include<string.h>3 #include<sys/types.h>4 #include<sys/stat.h>5 #include<fcntl.h>6 #include<unistd.h>7 int main()8 {9 char *str1="normal message\n";10 char *str2="error message\n";11 write(1,str1,strlen(str1));12 write(2,str2,strlen(str2)); 13 return 0;14 }
我们的程序分别向标准输出、标准错误打印不同的信息
现在我们的程序成功执行,并且都打印在了显示器上,这也是符合预期的,我们要想利用标准输出、标准错误需要利用重定向的操作:
在我们刚开是学习Linux指令(如:cat、echo等)时一定听说过重定向,默认方式为输出重定向。
下面这种方式我们就是将向标准输出打印的数据重定向到normal.txt
文件中,将向标准错误打印的信息重定向到err.txt
文件中,这样我们就完成了信息分类的工作,那么为什么要这样呢?标准错误,大家想在我们执行程序是,我们是十分重视错误信息的,若是可以将错误信息与正常信息分离,这对我们的开发效率还是比较友好的。下面我们看如何实现的,我们先来看下面这个场景:
1 #include<stdio.h>2 #include<string.h>3 #include<sys/types.h>4 #include<sys/stat.h>5 #include<fcntl.h>6 #include<unistd.h>7 int main()8 { 9 close(1);10 char *str1="normal message\n";11 char *str2="error message\n";12 write(1,str1,strlen(str1));13 write(2,str2,strlen(str2));14 return 0;15 }
我们使用close
关闭标识符为1的文件,程序执行结果:
文件描述符1和2,虽然都是对应显示器文件,但是其底层利用引用计数方式来实现,每当多一个文件描述符指向文件,文件所拥有的引用计数就会增减一,相反每当有一个文件描述符关闭,对应文件的文件描述符就会减小一,当文件引用计数为零时,文件就会被关闭。
二、文件描述符分配规则
1 #include<stdio.h>2 #include<string.h>3 #include<sys/types.h>4 #include<sys/stat.h>5 #include<fcntl.h>6 #include<unistd.h>7 int main()8 {9 close(0);10 int fd1=open("ll.txt",O_WRONLY|O_CREAT,0666);11 int fd2=open("gg.txt",O_WRONLY|O_CREAT,0666);12 printf("fd1:%d fd2:%d\n",fd1,fd2); 13 return 0;14 }
我们知道操作系统默认的三个文件描述符为:0、1、2,现在我们关闭标准输入并且打开两个新的文件,查看文件描述符:
此时文件描述符变为0、3,这是因为当你新打开一个文件时,操作系统会在file_struct
数组中,找到当前没有被使用的最小下标,并将文件地址存入下表对应空间,返回下标作为新的文件描述符,这里你可以进行多次尝试验证。
三、文件重定向
我们看下面这个简单的程序:
1 #include<stdio.h>2 #include<string.h>3 #include<sys/types.h>4 #include<sys/stat.h>5 #include<fcntl.h>6 #include<unistd.h>7 int main()8 {9 close(1);10 int fd=open("gg.txt",O_WRONLY|O_CREAT);11 printf("%d\n",fd);12 return 0;13 }
结合我们上面介绍的,关闭文件描述符1,此时打开文件gg.txt
,1就会为gg.txt
的描述符。
可以看到本该打印在显示器上的信息,现在打印在了文件中,而产生这一现象的原因是因为对于printf
函数来说,它只是封装了1
号文件描述符,当程序执行它时,它就会将数据输出到1
号文件描述符对应的文件中,并不会关心该文件是谁,上面这种现象就被称为输出重定向,你也可以尝试关闭0
号文件描述符,让scanf
从文件中读取,这里就不演示了。
上面这种重定向的行为有一点搓,我们实际运用中一般使用dup2
函数来完成重定向工作。
dup2()函数
这个函数需要两个文件描述作为参数,它会用旧的文件描述符所存储的地址覆盖新的文件描述符处的地址,函数调用成功返回新的文件描述符,失败返回-1
man手册对这给函数描述更抽象,所以没有给大家展示,结合下图理解吧
下面我们来尝试使用:
1 #include<stdio.h>2 #include<string.h>3 #include<sys/types.h>4 #include<sys/stat.h>5 #include<fcntl.h>6 #include<unistd.h>7 int main()8 {9 int fd=open("gg.txt",O_WRONLY|O_CREAT);10 dup2(fd,1);11 printf("dup2(%d,%d)\n",fd,1); 12 return 0;13 }
我们用gg.txt
的文件描述符,覆盖文件描述符1
。
这样我们就可以利用系统调用完成重定向工作了,当然这只是输出重定向,大家可以尝试输入重定向,下面我们再次认识一下指令方面的重定向
7 int main()8 {9 char *str1="normal message\n";10 char *str2="error message\n";11 int fd1=open("normal.txt",O_WRONLY|O_CREAT,0666);12 int fd2=open("error.txt",O_WRONLY|O_CREAT,0666);13 write(1,str1,strlen(str1)); 14 write(2,str2,strlen(str2));15 return 0;16 }
./test 1>normal.txt 2>error.txt
上面我们演示了使用这个指令将他吗重定向到不太文件中,接下来我们演示如何重定向到同一文件中。
./test >myfile 2>&1
这句指令的意思就是将test
的执行结果进行输出重定向,并且使用文件描述符1
覆盖文件描述符2
,这就是对dup2(1,2)
的分装,具体原理我们上面已经介绍过了。
四、Linux下一切皆文件
当我们学到这里,就可以理解Linux下一切皆文件
的概念了,我们知道计算机的所有操作都是通过进程来完成的,那么对硬件的操作(打开、写入等)也必然是这样,这是如何做到的呢?毕竟每个硬件的操作方式都各有特点(有的可以些,有的只能读。,操作系统将外设全部抽象化,使用结构体来描述他们的属性,虽然属性不同,但是属性的种类还是很接近的,所以操作系统给每个硬件都生成了一个struct_file
结构体(这个结构体我们上篇提到过),在结构体中有一个指针,指向一个struct peration_func
类型的结构体,这里面就是硬件具体操作方法的指针(函数指针),指针指向每个硬件具体的操作方法,而每个硬件都会提供一个自己的操作方法。
这里将底层实现差异屏蔽,对上提供相同接口的形式,实现了一切接文件的概念。可以说c++中的继承、多态,就像这里的设计思路一样。
相关文章:
Linux文件描述符的分配机制与重定向实现:揭开“一切皆文件”的面纱
Linux系列 文章目录 Linux系列前言一、Linux的标准流二、文件描述符分配规则三、文件重定向四、Linux下一切皆文件 前言 上篇我们介绍了语言和系统层次的基础I/O文件操作,其涉及的知识有:C语言文件操作和系统调用接口两者的关系、文件描述符的概念、操作…...
SpringBoot事务管理(四)
记录几条SpringBoot事务管理中踩过的坑及解决办法: 1. 自调用问题 问题描述 在同一个类中,一个非事务方法调用另一个有 Transactional 注解的事务方法,事务不会生效。因为 Spring 的事务管理是基于 AOP 代理实现的,自调用时不会…...
iOS GCD
GCD 任务队列 主队列: 任务在主线程执行,主队列是一个串行队列,它主要处理 UI 相关任务,也可以处理其他类型任务,但为了性能考虑,尽量让主队列执行 UI 相关或少量不耗时间和资源的操作。 系统全局并发队…...
Hadoop集群的常用命令
1.基本命令 启动 Hadoop: start-dfs.sh start-yarn.sh 这些命令会分别启动 Hadoop 的 DFS 和 YARN。 查看 Hadoop 目录: hdfs dfs -ls -R / 该命令会递归地列出 HDFS 根目录下的所有文件和目录。 创建目录: hdfs dfs -mkdir /example_dir 在 HDFS 中创建一个新目录。 上传文…...
Kafka 实战指南:原理剖析与高并发场景设计模式
一、介绍 Kafka是由 Apache 软件基金会开发的开源流处理平台,作为高吞吐量的分布式发布订阅消息系统,采用 Scala 和 Java 编写。 Kafka是一种消息服务(MQ),在理论上可以达到十万的并发。 代表的MQ软件—— kafka 十万…...
黑盒测试的判定表法(能对多条件依赖关系进行设计测试点)
定义: 判定表是分析和表达多逻辑条件下执行不同操作的工具。就是指把所有的输入条件、所有可能采取的动作按表格列出来,每一种条件和动作的组合构成一条规则,也即一条用例。 1.判定表法的引用 等价类边界值分析法主要关注单个输入类条件的测试并未考虑…...
SQLMesh系列教程:基于指标构建一致的分析语义层应用实践
本文深入探讨SQLMesh指标框架的核心概念、定义方法及应用场景。通过统一的语义层管理,SQLMesh解决了数据分析中指标定义不一致的痛点,实现了跨团队协作的数据一致性。文章包含指标定义语法详解、自动表连接机制解析、派生指标构建方法,并通过…...
解决Docker端口映射后外网无法访问的问题
一、前言 今天因为服务器宕机,重新启动后发现docker部署的mysql和redis都无法通过外网访问。经过排查原因是ip转发没有开启。下面教大家如何解决 二、问题排查 (1) 查看防火墙运行情况 使用firewall-cmd --state 如果防火墙处于not running,则可以排…...
如何指定运行amd64架构的ubuntu?
如何指定运行amd64架构的ubuntu 下面这个命令如何制定运行amd64架构的ubuntu? docker run -it -v $(pwd):/workspace ubuntu:20.04 bash这个命令已经非常接近正确运行一个基于 amd64 架构的 Ubuntu 容器了,但如果你想明确指定运行 amd64 架构的镜像&am…...
[MySQL]数据类型
数据类型 1.数据类型分类2.数值类型2.1 tinyint类型无符号类型举例 3.bit类型3.1 基本语法 4. 小数类型4.1 float语法4.2 decimal语法 5.字符串类型5.1 char类型5.2 varchar 6.日期类型7.enum和set查询语句 1.数据类型分类 接下来就对上面的四种类型进行介绍 2.数值类型 数值类…...
基于Python的Django框架的手机购物商城管理系统
标题:基于Python的Django框架的手机购物商城管理系统 内容:1.摘要 随着互联网的快速发展,手机购物逐渐成为人们日常生活中不可或缺的一部分。本研究的目的是开发一个基于Python的Django框架的手机购物商城管理系统,以提高购物商城的管理效率和用户体验。…...
大模型在2型糖尿病预测及围手术期管理中的应用研究
目录 一、引言 1.1 研究背景与意义 1.2 国内外研究现状 1.3 研究目的与创新点 二、大模型预测 2 型糖尿病的原理与方法 2.1 大模型概述 2.2 用于 2 型糖尿病预测的大模型类型 2.3 模型训练与数据来源 2.4 预测指标与算法 三、术前风险预测与评估 3.1 血糖控制情况预…...
JavaEE--多线程
一、认识线程 1. 什么是线程 线程(Thread)是计算机科学中的基本概念,指的是程序内部的一条执行路径。一个进程可以包含多个线程,每个线程共享进程的资源,包括内存空间、文件描述符等。线程可以同时执行多个任务&…...
自动化测试之等待方式
在自动化测试中,等待是一个重要的技术,用于处理页面加载、元素定位、元素状态改变等延迟问题。 等待能够确保在条件满足后再进行后续操作,提高自动化测试的稳定性以及可靠性。 等待方式:显示等待、隐式等待、线程睡眠 1. 显式等…...
git中用于生成commitId与其父commitId间的文件差异文件树
生成commitId与其父commitId间的文件差异文件树 #!/bin/bash # # 用于生成目标commitId与其父commitId间文件差异 # commit_id$1 # 输入目标commit的哈希值 old_dir"old_version" new_dir"new_version"# 创建目录 mkdir -p "$old_dir" "$…...
Ubuntu / Debian 创建快捷方式启动提权
简述 在 Linux 系统中,.desktop 文件是 桌面入口文件,用于在桌面环境(如 GNOME、KDE)中定义应用程序的启动方式、图标、名称等信息。当你执行 touch idea.desktop 时,实际上创建了一个空的 .desktop 文件(…...
VLA 论文精读(三)Diffusion Policy: Visuomotor Policy Learning via Action Diffusion
这篇笔记用来描述 2023年 发表在arxiv上的一篇有关VLA领域的论文,这篇笔记记录的是该论文 2024年03月的改版后。 写在最前面 为了方便你的阅读,以下几点的注意事项请务必了解: 该系列文章每个字都是我理解后自行翻译并写上去的,…...
ASP.NET Core 中实现 SSE 流式响应的简单例子
[HttpGet] public async Task<IActionResult> SseExample() {// 请求头Response.Headers.Add("Content-Type", "text/event-stream");Response.Headers.Add("Cache-Control", "no-cache");Response.Headers.Add("Connectio…...
「Unity3D」TMP_InputField关闭虚拟键盘后,再次打开虚拟键盘,此时无法回调onSelect的问题
TMP_InputField可以注册一个onSelect回调函数,在InputField选中的时候回调,但在虚拟键盘手动关闭或被返回取消的时候,此时再打开虚拟键盘时,就不会调用onSelect。 原因在于,虚拟键盘有三种关闭的操作方式:…...
手工排查后门木马的常用姿势
声明!本文章所有的工具分享仅仅只是供大家学习交流为主,切勿用于非法用途,如有任何触犯法律的行为,均与本人及团队无关!!! 1. 检查异常文件 (1)查找最近修改的文件 # 查…...
VRRP协议
基础概念 Master 路由器:“Master 路由器”在一个 VRRP 组中承担报文转发任务。在每一个 VRRP 组中,只有 Master 路由器才会响应针对虚拟 IP 地址的 ARP Request。Master 路由器会以一定的时间间隔周期性地发送 VRRP 报文,以便通知同一个 VRRP 组中的 B…...
【JavaEE】MyBatis 综合练习(图书管理系统)
目录 一、数据库表二、引入依赖:三、Model创建四、用户登录五、添加图书六、图书列表七、修改图书八、删除图书九、批量删除十、强制登录 图书管理系统 一、数据库表 我们使用两张表,一张用户表uset_test来记录登录的用户信息,一张图书表boo…...
ArkUI —— 组件导航
创建导航页 // src\main\ets\pages\Index.ets Entry Component struct Index {// 路由栈Provide(pathInfos) pathInfos: NavPathStack new NavPathStack()build() {Navigation(this.pathInfos) {}} }创建导航子页 this.navPath.pushPathByName(AccountTag, 账本分类管理)// …...
数据处理与机器学习入门
一、数据处理概述 数据处理是通过统计学、机器学习和数据挖掘方法从原始数据中提取有价值信息的过程。数据处理的目标是将杂乱无章的原始数据转化为可用于分析和建模的结构化数据。对于小规模数据处理,常用工具分为两类: • 可视化分析工具:…...
Markdown在线转word格式
1、打开网址 https://dillinger.io/ 2、输入markdown格式文章 3、直接转换为右边的word格式 4、复制粘贴即可。...
Redis延时队列在订单超时未报到场景的应用分享
一、引言 在电商、医疗预约等众多业务场景中,经常会遇到需要处理超时任务的情况。比如医疗预约订单,如果患者在支付成功后,到了预约结束时间还未报到,系统需要自动取消订单。为了实现这样的功能,我们可以利用 Redis 延…...
vue前端代码作业——待办事项
美化样式示意图: 后端IDEA代码示意图: 代码解释: 1. isAllChecked 计算属性的作用 isAllChecked 用于实现 “全选 / 全不选” 功能,它是一个 双向绑定 的计算属性(因为 v-model 需要同时支持读取和设置值)…...
docker镜像拉取失败
hub.docker.com中提供的docker pull命令在服务器拉取镜像时报错Error response from daemon: Get https://registry-1.docker.io/v2/: net/http: request canceled while waiting for connection (Client.Timeout exceeded while awaiting headers) 这个错误通常表明Docker客户…...
Ruby 简介
Ruby 简介 引言 Ruby 是一种广泛使用的动态、开源的编程语言,自 1995 年由日本程序员 Yukihiro Matsumoto(通称 Matz)设计以来,它以其优雅的语法、强大的库支持和跨平台特性赢得了全球开发者的青睐。本文将详细介绍 Ruby 的起源、特点、应用领域以及它在现代软件开发中的…...
解决 FFmpeg 使用 C/C++ 接口时,解码没有 shell 快的问题(使用多线程)
一、问题 硬件设备为香橙派 5Plus,最近需要使用硬件视频解码来加速 YOLO 的检测,shell 窗口的FFmpeg已经调通,详见文章: 编译支持 RKmpp 和 RGA 的 ffmpeg 源码_rk3588 ffmpeg mpp-CSDN博客https://blog.csdn.net/plmm__/article…...
sqlalchemy:将mysql切换到OpenGauss
说明 之前python的项目使用的mysql,近期要切换到国产数据库OpenGauss。 之前的方案是fastapisqlalchemy,测试下来发现不用改代码,只要改下配置即可。 切换方案 安装openGauss-connector-python-psycopg2 其代码工程在:https:…...
缓存使用纪要
一、本地缓存:Caffeine 1、简介 Caffeine是一种高性能、高命中率、内存占用低的本地缓存库,简单来说它是 Guava Cache 的优化加强版,是当下最流行、最佳(最优)缓存框架。 Spring5 即将放弃掉 Guava Cache 作为缓存机…...
Qt之Service开发
一、概述 基于Qt的用于开发系统服务(守护进程)和后台服务,有以下几个优秀的开源 QtService 框架和库。 1. QtService (官方解决方案) GitHub: https://github.com/qtproject/qt-solutions/tree/master/qtservice 特点: 官方提供的服务框架 支持 Windows 服务和 Linux 守护…...
ssm框架之Spring
Spring框架介绍 Spring框架是一个轻量级的企业级应用框架 通过它可以贯穿表现层、业务层、持久层。集成方便,简单易用,具有如下特点: Spring框架特色 Spring设计理念 是面向Bean的编程 Spring两大核心技术 控制反转(IoC:Inver…...
Flutter 开发环境配置--宇宙级教学!
目录 一、安装环境(Windows)二、Android 创建Flutter项目三、VSCode 搭建环境四、补充 一、安装环境(Windows) Flutter SDK 下载 推荐使用中国镜像站点下载 Flutter SDK,速度更快:中国环境 或者从官网下载…...
音视频 YUV格式详解
前言 本文介绍YUV色彩模型,YUV的分类和常见格式。 RGB色彩模型 在RGB颜色空间中,任意色光F都可以使用R、G、B三色不同的分量混合相加而成即: F = R + G + B.。即我们熟悉的三原色模型。 RGB色彩空间根据每个分量在计算机中占用的存储字节数可以分为以下几种类型,字节数…...
力扣 第 153 场双周赛 讲题
文章目录 Q1.字符串的反转度Q2.操作后最大活跃区段数I3500.将数组分割为子数组的最小代价 Q1.字符串的反转度 签到题,直接建立一个映射表即可 class Solution:def reverseDegree(self, s: str) -> int:# 先建立映射表ss "abcdefghijklmnopqrstuvwxyz"store {}i…...
grafana 配置页面告警
添加告警规则 1.登录grafana 点击 Alerting > Alert rules 点击 New alert rule 2.填写告警规则名字 3.配置告警规则 选择数据源为 Loki 单机 Builder 单机Label brower 单机 node_name 标签,选择一个主机,选好后单机 Show logs 这时候查询语…...
Cent OS7+Docker+Dify
由于我之前安装了Dify v1.0.0,出现了一些问题:无法删除,包括:知识库中的文件、应用、智能体、工作流,都无法删除。现在把服务器初始化,一步步重新安装,从0到有。 目录 1、服务器重装系统和配置…...
【自学笔记】PHP语言基础知识点总览-持续更新
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 1. PHP 简介2. PHP 环境搭建3. 基本语法变量与常量数据类型运算符 4. 控制结构条件语句循环语句 5. 函数函数定义与调用作用域 6. 数组7. 字符串8. 表单处理9. 会话…...
Android Gradle 下载插件或依赖太慢
问题与处理策略 问题描述 Android 项目中,settings.gradle 文件中,有如下配置,Gradle 插件或依赖下载速度慢 pluginManagement {repositories {gradlePluginPortal()google()mavenCentral()} }dependencyResolutionManagement {repositori…...
python-59-基于python内置库解析html获取标签关键信息
文章目录 1 html.parser1.1 初始化和基础使用1.1.1 handle_starttag(self, tag, attrs)1.1.2 handle_endtag(self, tag)1.1.3 handle_startendtag(self, tag, attrs)1.1.4 handle_data(self, data)1.1.5 handle_comment(self, data)1.2 解析HTML文档的流程2 百度搜索关键词链接…...
elementplus的el-tabs路由式
在使用 Element Plus 的 el-tabs 组件,实现路由式的切换(即点击标签页来切换不同的路由页面)。下面是一个基于 Vue 3 和 Element Plus 实现路由式 el-tabs 的基本步骤和示例。 步骤 1: 安装必要的库 在vue3项目安装 Vue Router 和 Element …...
ArcGIS地理信息系统空间分析实验教程学习
ArcGIS 作为地理信息系统领域的经典软件,以其强大的功能和广泛的应用场景,成为了众多学者、研究人员和专业人士的首选工具。它不仅可以高效地处理和可视化地理空间数据,还能通过复杂的空间分析模型,揭示地理现象背后的规律和趋势。…...
mac部署CAT监控服务
在 Mac 上部署美团点评开源的 CAT 监控服务端,可以按照以下步骤操作: 1. 环境准备 1.1 安装依赖 确保已安装以下工具: JDK 8(建议 OpenJDK 11) MySQL 5.7(存储监控数据)(8.0不支持…...
鸿蒙OS 5 架构设计探秘:从分层设计到多端部署
文章目录 鸿蒙OS架构设计探秘:从分层设计到多端部署一、鸿蒙的分层架构设计二、模块化设计的精髓三、智慧分发设计:资源的动态调度四、一次开发,多端部署的实践总结与思考 鸿蒙OS架构设计探秘:从分层设计到多端部署 最近两年来&a…...
深入解析:ElasticSearch Query 查询方式
全文目录: 开篇语前言摘要概述ElasticSearch Query 查询方式详解1. Match 查询(全文搜索)1.1 Match 查询示例1.2 Match 查询参数扩展 2. Term 查询(精准查询)2.1 Term 查询示例2.2 Terms 查询 3. Bool 查询(…...
HTML5贪吃蛇游戏开发经验分享
HTML5贪吃蛇游戏开发经验分享 这里写目录标题 HTML5贪吃蛇游戏开发经验分享项目介绍技术栈核心功能实现1. 游戏初始化2. 蛇的移动控制3. 碰撞检测4. 食物生成 开发心得项目收获后续优化方向结语 项目介绍 在这个项目中,我使用HTML5 Canvas和原生JavaScript实现了一…...
桥接模式_结构型_GOF23
桥接模式 桥接模式(Bridge Pattern)是一种结构型设计模式,核心思想是将抽象与实现分离,使两者能独立变化。它像一座连接两岸的桥梁,让“抽象层”和“实现层”自由组合,避免因多维度变化导致的“类爆炸”问…...
卡尔曼滤波入门(二)
核心思想 卡尔曼滤波的核心就是在不确定中寻找最优,那么怎么定义最优呢?答案是均方误差最小的,便是最优。 卡尔曼滤波本质上是一种动态系统状态估计器,它回答了这样一个问题: 如何从充满噪声的观测数据中,…...