【Linux】C文件系统详解(二)——什么是fd文件描述符以及理解“一切皆文件“

文章目录

  • fd-文件描述符
  • 如何深度理解"一切皆文件"
    • **我们使用OS的本质:**
    • FILE
      • `FILE`是什么?谁提供的?和我们刚刚讲的内核的struct有关系吗
        • `FILE`是一个结构体.该结构体内部一定要有以下字段:
        • `FILE`是C语言标准库提供的.
        • `FILE`和我们刚刚讲的内核的struct没有关系,最多就是上下层的关系
    • 做实验->重定向的本质
      • 第一个实验->文件描述符的分配规则
      • 第二个实验->输出重定向
        • 重定向的原理
      • 第三个实验->输入重定向
      • 第四个实验->追加重定向
      • 结论
        • 需求:把常规消息放一个文件,错误消息放在另一个文件
        • 更好的写法
    • 让我们自己的程序支持重定向:

fd-文件描述符

任何一个进程,在启动的时候,默认会打开当前进程的三个文件

标准输入标准输出标准错误本质都是文件
stdinstdoutstderr文件在语言层的表现
cincoutcerr同上,但是他是一个类
012<-fd ,数组下标

文件描述符,即open对应的返回值,本质就是:数组下标
标准输出和标准错误都会向显示器打印,但是其实是不一样的

类型设备文件
标准输入键盘文件
标准输出显示器文件
标准错误显示器文件
#include<iostream>
#include<cstdio>int main()
{//因为linux一切皆文件,所以,向显示器打印,本质就是向文件中写入printf("hello printf->stdout\n");	fprintf(stdout,"hello fprintf->stdout\n");fprintf(stderr,"hello fprintf->stderr\n");std::cout << "hello cout -> cout" << std::endl;std::cerr << "hello cerr -> cerr" << std::endl;
}
int fd1 = open(LOG,O_WRONLY | O_CREAT | O_TRUNC,0666);//3
int fd2 = open(LOG,O_WRONLY | O_CREAT | O_TRUNC,0666);//4
int fd3 = open(LOG,O_WRONLY | O_CREAT | O_TRUNC,0666);//5
int fd4 = open(LOG,O_WRONLY | O_CREAT | O_TRUNC,0666);//6
int fd5 = open(LOG,O_WRONLY | O_CREAT | O_TRUNC,0666);//7
int fd6 = open(LOG,O_WRONLY | O_CREAT | O_TRUNC,0666);//8

![[Drawing 2023-11-08 11.12.05.excalidraw|900]]

如何深度理解"一切皆文件"

我们使用OS的本质:

都是通过进程的方式进行操作系统的访问,在进程的角度,只能看到文件对象,而看不到底层的设备的区别,所以我们才说"Linux下一切皆文件".
![[文件系统 2023-03-18 15.19.03.excalidraw|800]]

FILE

操作系统层面,我们必须使用fd才能找到文件!
任何语言层面访问外设或者文件,都必须经历OS

FILE是什么?谁提供的?和我们刚刚讲的内核的struct有关系吗

#include<stdio.h>
FILE* fopen(const char *path,const char* mode);

答案:

FILE是一个结构体.该结构体内部一定要有以下字段:
fd

证明:

int main()
{printf("%d\n",stdin->_fileno);printf("%d\n",stdout->_fileno);printf("%d\n",stderr->_fileno);FILE* fp = fopen(LOG,"w");printf("%d\n",fp->_fileno);
}
FILE是C语言标准库提供的.

我们平时安装VS2019,是在安装IDE环境以及对应语言的库和头文件

FILE和我们刚刚讲的内核的struct没有关系,最多就是上下层的关系

做实验->重定向的本质

第一个实验->文件描述符的分配规则

把fd为3的文件关闭以后,新的文件fd应该是什么

int main()
{close(0);//fclose(stdin)close(2);//fclose(stderr)int fd1 = open(LOG,O_WRONLY | O_CREAT | O_TRUNC,0666);int fd2 = open(LOG,O_WRONLY | O_CREAT | O_TRUNC,0666);int fd3 = open(LOG,O_WRONLY | O_CREAT | O_TRUNC,0666);int fd4 = open(LOG,O_WRONLY | O_CREAT | O_TRUNC,0666);int fd5 = open(LOG,O_WRONLY | O_CREAT | O_TRUNC,0666);int fd6 = open(LOG,O_WRONLY | O_CREAT | O_TRUNC,0666);printf("%d\n",fd1);0printf("%d\n",fd2);2printf("%d\n",fd3);3printf("%d\n",fd4);4printf("%d\n",fd5);5return 0;
}

进程中,文件描述符的分配规则:

最小的,没有被使用的数组元素,分配给新文件

第二个实验->输出重定向

int main()
{fclose(1);int fd = open(LOG, O_WRONLY | O_CREAT | O_TRUC, 0666);//此时log.txt的fd是'1'//但是上层结构不知道这个变化,他只知道要写进fd=1的文件中printf("you can see me!\n");//本来是指向stdout -> 1的,但是stdout变成了log.txtprintf("you can see me!\n");printf("you can see me!\n");printf("you can see me!\n");printf("you can see me!\n");return 0;
}

结果:打印不到屏幕,但是打印到了log.txt
printf("",);不是认stdout,而是认fd==1的文件描述符

重定向的原理

在上层无法感知的情况下,在OS内部,更改进程对应的文件描述符表中,特定下标的指向!!

第三个实验->输入重定向

现在log.txt中写入:

123 456
int main()
{fclose(0);int fd = open(LOG, O_RDONLY | O_CREAT | O_TRUC, 0666);//fd=0int a,b;scanf("%d %d",&a,&b);printf("a=%d , b=%d\n",a,b);return 0;
}

结果: cat log.txt:
a=123 , b=456

第四个实验->追加重定向

int main()
{close(1);//标准输出int fd = open(LOG, O_RDONLY | O_CREAT | O_APPEND, 0666);printf("you can see me!\n");//从屏幕(stdout)上追加到fd中printf("you can see me!\n");printf("you can see me!\n");printf("you can see me!\n");
}

结果: cat log.txt:

a=123 , b=456
you can see me!
you can see me!
you can see me!
you can see me!

结论

所以stdout cout->1,他们都是向1号文件描述符对应的文件打印
stderr cerr ->2 ,他们都是向2号文件描述符对应的文件打印
输出重定向,只改的是1号对应的指向,对2号不影响

需求:把常规消息放一个文件,错误消息放在另一个文件
#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
#include<errno.h>
#include<string.h>
#define LOG "log.txt"
#define LOG_NORMAL "logNormal.txt"
#define LOG_ERROR "logError.txt"int main()
{close(1);int fd = open(LOG_NORMAL, O_WRONLY | O_CREAT | O_APPEND, 0666);close(2);int fd = open(LOG_ERROR, O_WRONLY | O_CREAT | O_APPEND, 0666);printf("hello printf->stdout\n");	fprintf(stdout,"hello fprintf->stdout\n");fprintf(stderr,"hello fprintf->stderr\n");}

所以为什么要默认把1和2打开:
就是为了把常规消息和错误消息分类开来,便于后面的调试!

bash中重定向操作

a.out > log.txt 2 > &1
或者
a.out 1>log.txt 2>err.txt

2 > &1
把1里面的内容,写到2下标的内容里

更好的写法

int dup2(int oldfd, int newfd)
是对数组对应下标的内容进行拷贝

new要成为old的拷贝
所以最终只有oldfd的内容了
而我们最后正确重定向肯定是剩下3啊
所以oldfd 是3
newfd 是1

所以代码
dup2(fd,1)

重定向写法:

int main ()
{int fd = open(LOG_NORMAL, O_WRONLY | O_CREAT | O_APPEND, 0666);if(fd < 0){perrer("open");return 1;}dup2(fd,1);printf("hello world,hello lx\n");close(fd);
}

就是打开文件,之后使用dup2就行

让我们自己的程序支持重定向:

enum redir{REDIR_INPUT = 0,REDIR_OUTPUT,REDIR_APPEND,REDIR_NONE
};char* checkdir(char commandstr[],redir &redir_type);
{//1.监测是否有 > < >> //2.如果有,要根据> < >> 设置redir_type = ?//3.将符号改成\0,分成两部分//保存文件名,并返回//如果不满足,直接返回
}int main()
{while(1){redir redir_type = REDIR_NONE//...char* filename = NULL;char* filename = checkdir(commandstr,&redir_type);if(*filename){//1.存在文件//2.获取redir_type}//遍历,看是否有> < >>,这三个字符//前半部分执行后续//把这三个字符变成\0,将后面的字符串打开文件//dup2(fd,1);//...if(id == 0){if(redir_typr != REDIR_NONE){dup2();}}}
}

未完待续…

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/146562.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【STM32】串口和printf

1.数据通信的基本知识 1.串行/并行通信 2.单工/半双工/全双工通信 类似于【广播 对讲 电话】 不是有两根线就是全双工&#xff0c;而是输入和输出都有对应的数据线。 3.同步/异步通信 区分同步/异步通信的根本&#xff1a;判断是否有时钟信号&#xff08;时钟线&#xff09;。…

ai剪辑矩阵系统源码+无人直播系统源码技术开发

开发AI剪辑矩阵系统和无人直播系统源码&#xff0c;需要以下步骤&#xff1a; 1. 市场调研&#xff1a;了解市场需求和竞品情况&#xff0c;明确系统的功能和特点。 2. 系统设计&#xff1a;设计系统的整体架构和功能模块&#xff0c;包括视频剪辑、直播推流、实时互动、数据分…

【LeetCode刷题-滑动窗口】-- 795.区间子数组个数

795.区间子数组个数 class Solution {public int numSubarrayBoundedMax(int[] nums, int left, int right) {return lessEqualsThan(nums,right) - lessEqualsThan(nums,left - 1);}private int lessEqualsThan(int[] nums,int k){int len nums.length;int res 0,left 0,ri…

基于Genio 700 (MT8390)芯片的AR智能眼镜方案

AR眼镜是一种具有前所未有发展机遇的设备&#xff0c;无论是显示效果、体积还是功能都有明显的提升。AR技术因其智能、实时、三维、多重交互和开放世界的特点备受关注。 AR眼镜集成了AR技术、语音识别、智能控制等多项高科技功能&#xff0c;可以帮助用户实现更加便捷、高效、个…

一种基于NB‑IOT的粮库挡粮门异动监测装置

一种基于NB‑IOT的粮库挡粮门异动监测装置,包括若干个NB‑IOT开门监测装置、物联网后台管理系统、NB‑IOT低功耗广域网络和用户访问终端;各个NB‑IOT开门监测装置通过NB‑IOT低功耗广域网络与物联网后台管理系统连接,物联网后台管理系统与用户访问终端连接。 我国以往粮食收储…

将 ONLYOFFICE 文档编辑器与 Node.js 应用集成

我们来了解下&#xff0c;如何将 ONLYOFFICE 文档编辑器与您的 Web 应用集成。 许多 Web 应用都可以从文档编辑功能中获益。但是要从头开始创建这个功能&#xff0c;需要花费大量时间和精力。幸运的是&#xff0c;您可以使用 ONLYOFFICE——这是一款开源办公套件&#xff0c;可…

一文总结MySQL的指令是如何工作的

当你输入一条MySQL指令时候有没有想过会发生什么&#xff1f; 建立连接 首先你得先连到数据库上才行&#xff0c;这又分为长连接和短链接&#xff0c;短链接就是你查询一次就断开连接&#xff0c;长连接是你可以多次查询直到主动断开连接&#xff08;也可能被杀死进程&#x…

C语言——冒泡排序

一、冒泡排序是什么 冒泡排序&#xff1a; 冒泡排序(Bubble Sort)&#xff0c;又被称为气泡排序或泡沫排序。升序时&#xff1a;它会遍历若干次需要排序的数列&#xff0c;每次遍历时&#xff0c;它都会从前往后依次的比较相邻两个数的大小&#xff1b;如果前者比后者大&#x…

三十二、W5100S/W5500+RP2040树莓派Pico<UPnP示例>

文章目录 1 前言2 简介2 .1 什么是UPnP&#xff1f;2.2 UPnP的优点2.3 UPnP数据交互原理2.4 UPnP应用场景 3 WIZnet以太网芯片4 UPnP示例概述以及使用4.1 流程图4.2 准备工作核心4.3 连接方式4.4 主要代码概述4.5 结果演示 5 注意事项6 相关链接 1 前言 随着智能家居、物联网等…

centos虚拟机无法接受消息(防火墙)

1.利用wireshark抓包&#xff0c; 发现发送信息后&#xff0c; 虚拟机返回 :host administratively prohibited 2.发现是centos虚拟机未关闭防火墙 &#xff08;关闭后可正常接收消息&#xff09;

rabbitMQ的Topic模式的生产者与消费者使用案例

topic模式 RoutingKey 按照英文单词点号多拼接规则填充。其中消费者匹配规则时候 * 代表一个单词&#xff0c;#表示多个单词 消费者C1的RoutingKey 规则按照*.orange.* 匹配 绑定队列Q1 package com.esint.rabbitmq.work05;import com.esint.rabbitmq.RabbitMQUtils; import …

AI机器学习实战 | 使用 Python 和 scikit-learn 库进行情感分析

专栏集锦&#xff0c;大佬们可以收藏以备不时之需 Spring Cloud实战专栏&#xff1a;https://blog.csdn.net/superdangbo/category_9270827.html Python 实战专栏&#xff1a;https://blog.csdn.net/superdangbo/category_9271194.html Logback 详解专栏&#xff1a;https:/…

OpenCV C++ 图像处理实战 ——《OCR字符识别》

OpenCV C++ 图像处理实战 ——《OCR字符识别》 一、结果演示二、tesseract库配置2.1下载编译三、OCR字符识别3.1 文本检测方式3.1.1 RIL_BLOCK3.1.2 RIL_PARA3.1.3 RIL_TEXTLINE3.1.4 RIL_WORD3.1.5 RIL_SYMBOL3.2 英文文本检测3.3 中英文本检测四、源码测试图像下载总结一、结…

Springboot+vue的学生成绩管理系统(有报告),Javaee项目,springboot vue前后端分离项目。

演示视频&#xff1a; Springbootvue的学生成绩管理系统&#xff08;有报告&#xff09;&#xff0c;Javaee项目&#xff0c;springboot vue前后端分离项目。 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家…

开源与闭源:驾驭大模型未来的关键决断

在数字化的时代洪流中&#xff0c;开源与闭源的选择不断成为技术界的重要分水岭。随着特斯拉CEO埃隆马斯克的言论及其决策&#xff0c;公开支持开源&#xff0c;并糅合商业理念与技术革新&#xff0c;使得这场辩论再次成为公众关注的焦点。那么&#xff0c;在这场关乎技术发展脉…

Adversarial Attacks on Neural Networks for Graph Data

Adversarial Attacks on Neural Networks for Graph Data----《针对图数据的神经网络的对抗攻击》 论文提出了两个问题&#xff1a; 1、属性图的深度学习模型容易受攻击吗&#xff1f; 2、他们的结果可靠吗&#xff1f; 回答这两个问题需要考虑到GNN的特性&#xff1a; ①关…

物联网赋能:WIFI HaLow在无线连接中的优势

在探讨无线网络连接时&#xff0c;我们不难发现&#xff0c;WIFI已经成为我们日常生活中不可或缺的一部分&#xff0c;承载了半数以上的互联网流量&#xff0c;并在家庭、学校、娱乐场所等各种场合广泛应用。然而&#xff0c;尽管WIFI4、WIFI5和WIFI6等协议无处不在&#xff0c…

Go ZIP压缩文件读写操作

创建zip文件 golang提供了archive/zip包来处理zip压缩文件&#xff0c;下面通过一个简单的示例来展示golang如何创建zip压缩文件&#xff1a; func createZip(filename string) {// 缓存压缩文件内容buf : new(bytes.Buffer)// 创建zipwriter : zip.NewWriter(buf)defer writ…

【网络安全】伪装IP网络攻击的识别方法

随着互联网的普及和数字化进程的加速&#xff0c;网络攻击事件屡见不鲜。其中&#xff0c;伪装IP的网络攻击是一种较为常见的攻击方式。为了保护网络安全&#xff0c;我们需要了解如何识别和防范这种攻击。 一、伪装IP网络攻击的概念 伪装IP网络攻击是指攻击者通过篡改、伪造I…

C/C++ 运用VMI接口查询系统信息

Windows Management Instrumentation&#xff08;WMI&#xff09;是一种用于管理和监视Windows操作系统的框架。它为开发人员、系统管理员和自动化工具提供了一种标准的接口&#xff0c;通过这个接口&#xff0c;可以获取有关计算机系统硬件、操作系统和应用程序的信息&#xf…