【Linux】Linux 操作系统 - 18 , 重谈文件(二) ~ 文件描述符和重定向原理 , 手把手带你彻底理解 !!!
文章目录
- ● 文件描述符
- 一 、Linux 系统对文件的管理(要知道)
- 二 、什么是文件描述符 fd ?
- 三 、再探文件被管理过程(重要)
- 四 、文件描述符 0 、1、2
- 1. 文件描述符的分配原则
- 2. 提前认识三个默认打开的文件
- ● 重定向原理(重要)
- 一 、重定向现象
- 二 、深入剖析重定向现象(重要)
- 1 . 重定向的本质是什么 ???
- 2 . 各种重定向实现原理
- 2.1 dup2 系统调用(理解 , 掌握)
- 2.2 输出重定向
- 2.3 输入重定向
- 2.4 追加重定向
- 3 . 重定向的原理(面试考)
- ● 正式谈三个默认打开的文件
- 一 、stderr
- 二 、重定向的使用(重要)(重点讲解标准错误)
- 1 . 重定向的完整写法
- 2 . 将错误信息和正常信息隔离(重要)
- 3 . 将错误信息和正常信息打印在一起
- 总结
● 文件描述符
篇章一中笔者提到了文件描述符的概念 , 本节就详细对其进行介绍 !
对以下系统调用中会涉及文件描述符的概念 :
write(int fd, ....) - write to a file descriptor - 文件描述符read( int fd, .... ) - read from a file descriptor - 文件描述符 close(int fd) - close a file descriptor - 文件描述符
一 、Linux 系统对文件的管理(要知道)
之前第一篇章提到操作文件 , 就是进程操作文件 ! 那么考虑一个问题 ???
在系统中一切皆文件 , 那么文件多了 , 要不要被管理呢 ???
答 : 文件要被管理 ! 那怎么管理呢 ??? 先描述 , 再组织 !
既然要描述 , 那么就会有数据结构吧 !
以下便是具体描述 :
二 、什么是文件描述符 fd ?
上面也提到了文件被管理是通过文件描述符表管理的 , 那这个文件描述符表是个什么呢 ???
文件描述符表是一个数组 !
文件描述符的本质就是数组的下标 ! , 即 : fd 的本质就是数组的下标 !
flies_struct
这个数据结构中包含一个结构体指针数组 , 这个数组就是文件描述符表 !
- 内核源代码中的 files_struct
struct files_struct {
....
....
....
....
....
....//其中包含一个结构体指针数组
struct file __rcu * fd_array[NR_OPEN_DEFAULT]; // 文件描述符表
};
每打开一个文件 , 就会有一个文件描述符来描述该文件 , 即 : 就会有一个指针指向该文件 !
三 、再探文件被管理过程(重要)
总结文件被管理的过程(面试可能考) :
记住一个图 :
所以 , 还可以得出一个结论 :
对文件内容的任何操作 , 必须先把文件的内容加载到内核对应的文件缓冲区内 , 避免频繁 I/O , 提高效率 !
四 、文件描述符 0 、1、2
有了以上的理解 , 现在便好介绍 0 , 1 , 2 了 .
笔者之前提过 , 系统会为每个文件分配一个文件描述符 , 每一个描述符对应一个文件 !
1. 文件描述符的分配原则
因为文件描述符是数组的下标 , 所以会有以下原则 :
找到 files_struct 数组中没有被使用的最小的下标 , 作为当前文件的描述符 !
注意 : 是最小的下标 !!!
/ fd 分配原则#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>int main()
{//close(0);//int fd = open("log.txt" , O_CREAT | O_WRONLY | O_TRUNC , 0666); //printf("fd : %d\n",fd); ********** 打印 0//close(2);//int fd = open("log.txt" , O_CREAT | O_WRONLY | O_TRUNC , 0666); //printf("fd : %d\n",fd); ********** 打印 2int fd = open("log.txt" , O_CREAT | O_WRONLY | O_TRUNC , 0666); printf("fd : %d\n",fd); ********** 打印 3return 0;
}
2. 提前认识三个默认打开的文件
之前笔者也讲过 , 系统会自动打开三个默认文件 !
这三个默认文件 , 分别对应 :
键盘 --- 文件描述符 0
显示器 --- 文件描述符 1
显示器 --- 文件描述符 2
观察一个现象
#include <stdio.h>
#include <unistd.h>int main()
{ printf("进入第一次输入 :\n");int a = 0;scanf("%d",&a);printf("%d\n",a);close(0);printf("进入第二次输入 :\n");int b = 10;scanf("%d",&b);printf("%d\n",b);return 0;
}
所以 , 上面完全可以印证文件描述符 0 对应的就是键盘文件(C语言 — stdin ) !
其余 , 学者可以自行验证 !
● 重定向原理(重要)
我们之前经常用 > , 这个就是重定向 , 那么其原理真的了解吗 ?
重定向分类 :
- 输出重定向
- 输入重定向
- 追加重定向
一 、重定向现象
给出以下代码 : 你会发现什么现象 ??
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>int main()
{ // 演示输出重定向现象 , 即 1 -- 对于 stdout// 关闭 1 对于的文件 , 即 : 关闭显示器文件close(1);int fd = open("redir.txt" , O_CREAT|O_WRONLY | O_APPEND , 0666);//打印 , 默认打印到显示器 , 即 : 只会向 1 设备文件中打印 ; 但当关闭 stdout 文件后 , 会打印到 redir.txt 中 printf("I am file , defalut printf to stdout\n");return 0;
}*************** 关闭 1 , 不会在显示器上打印了 , 而是打印在了 redir.txt 中 **************
二 、深入剖析重定向现象(重要)
对以上的现象 , 为什么关闭了 1 对应的文件 , 不会打印在显示器 , 却打印到了其它文件了呢 ??
1 . 重定向的本质是什么 ???
通过以上讲解的 , 现象的剖析 , 便可得到 :
重定向的本质 : 改变文件描述符的指针指向 !!!!
2 . 各种重定向实现原理
2.1 dup2 系统调用(理解 , 掌握)
这里介绍一个系统调用 :
dup, dup2, dup3 - duplicate a file descriptor , 复制一个文件描述符int dup2(int oldfd, int newfd);描述 : 使用新的 newfd 这个文件描述符 , 形成 oldfd 这个文件描述符的拷贝 !简单理解 : 它会将 oldfd 所指向的文件复制到 newfd,新的会指向旧的内容 !
2.2 输出重定向
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>// ls > xxx , 往 xxx 写入
int main()
{int fd = open("dir.txt" , O_CREAT | O_WRONLY | O_TRUNC , 0666);// old , new , 新的指向旧的 dup2(fd , 1); // 1 本身指向的是显示器文件 , 在 C语言中为 : stdout , 现在指向 fd printf("Hello newfile\n");const char* str = "dir success!\n";write(1 , str , strlen(str));close(fd); return 0;
}
通过我们手动编写的原理 , 这里就可以知道为什么 > 符号可以用来新建文件了 . 因为 open 文件时会 O_CREAT , 文件不存在 , 就创建 !
2.3 输入重定向
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>// ls < xxx , 从 xxx 读取内容
int main()
{int fd = open("dir.txt" , O_RDONLY);dup2(fd , 0); // 0 原来指向键盘文件 , 默认从键盘上读取内容, 现在指向 dir.txt char buff[200];memset(buff , 0 , sizeof(buff));//读 fd 文件 while(1) { // 从 0 指向的设备文件中读 ssize_t red = read(0 , buff , sizeof(buff)-1); // 不读 \0 l if(red > 0){buff[red] = 0;printf("%s\n",buff); } if(red == 0 ){break;}}return 0;
}
以上就做到了 , 本来是从键盘读取 , 现在是在新的文件中读取 !
2.4 追加重定向
这里实现一个追加输出重定向 .
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>/ 追加输出重定向
// ls >> xxx , 往 xxx 写入
int main()
{int fd = open("dir.txt" , O_CREAT | O_WRONLY | O_APPEND , 0666);// old , new , 新的指向旧的 dup2(fd , 1); // 1 本身指向的是显示器文件 , 在 C语言中为 : stdout , 现在指向 fd printf("Hello newfile\n");const char* str = "dir success!\n";write(1 , str , strlen(str));close(fd); return 0;
}
这里就可以发现 , 可以追加写入到 dir.txt 这个文件中了 !
3 . 重定向的原理(面试考)
通过以上各个重定向的编写 , 我们可以发现一个共同点 , 那就是每个重定向都是 : 打开方式 + dup2 来进行的 !
面试总结 :
● 正式谈三个默认打开的文件
在之前的篇章笔者一直在铺垫三个默认打开的文件 , 但是没有正式讲解 , 这里便给出 !
通过文件描述符的学习 , 我们这里就可以知道了 , 以下 :
- 键盘文件对应文件描述符 0
- 显示器文件(stdout) 对应文件描述符 1
- 显示器文件(stderr) 对应文件描述符 2
所以 , 默认情况下 , 0 , 1 , 2 是被占用的 , 我们之后打开的文件默认是从文件描述符 3 开始的 !
那对于 stderr 这个显示器文件一直没有介绍 , 以下对其详细解释 !
一 、stderr
stderr 是显示器文件 , 那么和 stdout 的显示器文件到底有什么区别呢 ??
- stdout 是显示器文件 , 一般显示我们正常的程序信息 .
- stderr 是显示器文件 , 一般显示我们错误的程序信息 .
- 二者本质都是指向同一个硬件 , 但是二者所对应的文件描述符不同 !
描述符不同 , 目的是让我们用重定向进行正常信息和错误信息的隔离 !!!
二 、重定向的使用(重要)(重点讲解标准错误)
1 . 重定向的完整写法
假如这里需要把可执行程序 a.out 里面的内容重定向到文件 log.txt 中 . 我们平时写的 x > log.txt 的完整写法是 :a.out 1 > log.txt // 解释
意思就是 : 把 a.out 里面的 1 文件描述符对应的内容重定向到 log.txt 中 .
这里看一段代码理解 :
#include <iostream>
#include <cstdio>int main()
{ //输出 , 默认是在显示器输出 , 1 对应的文件 ,stdout(C语言) , cout(C++)printf("Hello C!\n");std::cout << "Hello C++!" << std::endl;//输出错误信息 , 默认也是在显示器输出 , 1 对应文件 ,stderr , cerrconst char* str = "Hello C err!\n";fprintf(stderr , "%s" , str);std::cerr << "Hello C++ Err!" << std::endl;return 0;
}
- 编译后执行 , 不进行重定向 !
-
编译后执行 , 进行重定向 ! (不用完整写法)
-
编译后执行 , 进行重定向 ! (用完整写法)
所以 , 重定向时 , 可以指定文件描述符 , 这是最完整的写法 !!!
2 . 将错误信息和正常信息隔离(重要)
重定向完整写法的最大应用就是将二者进行隔离 , 这样方便程序员去查看错误信息 !
./mydir 1>log.normal 2>log.err
所以 , 要清楚
文件描述符 1 - > 对应的是显示器文件 , stdout / cout , 即 : 一般打印我们程序程序信息 !
文件描述符 2 - > 对于的是显示器文件 , stderr / cerr , 即 : 一般打印我们程序的错误信息 !
通过 重定向 可以将不同的信息打印到不同文件 ! 这是常做的 !!!!
3 . 将错误信息和正常信息打印在一起
当我们需要将二者信息同时都重定向到一个文件该怎么做 ???
可能有的人会这样做 :
.mydir 1>log.normal 2>log.normal // 这个有问题吗 ????????
上面的做法是有问题的 , 因为 > 底层是用的系统调用 open 呀 , open 的打开文件方式是用了 O_TRUNC 的 , 也就意味着会先清空在写入 , 所以 , 非常错误 !!!
正确做法
./mydir 1>log.normal 2>&1
2 > &1 的意思就是 : 再把 2 里面的内容添加到 1 里面 , 不清空 !
总结
相关文章:

【Linux】Linux 操作系统 - 18 , 重谈文件(二) ~ 文件描述符和重定向原理 , 手把手带你彻底理解 !!!
文章目录 ● 文件描述符一 、Linux 系统对文件的管理(要知道)二 、什么是文件描述符 fd ?三 、再探文件被管理过程(重要)四 、文件描述符 0 、1、21. 文件描述符的分配原则2. 提前认识三个默认打开的文件 ● 重定向原理(重要)一 、重定向现象二 、深入剖析重定向现象(重要)1…...

第五十三节:综合项目实践-车牌识别系统
一、项目背景与意义 车牌识别系统(LPR)是智能交通领域的核心技术之一,广泛应用于停车场管理、违章抓拍、高速公路收费等场景。本文将通过Python+OpenCV实现一个完整的车牌识别系统,涵盖图像预处理→车牌定位→字符分割→字符识别四大核心环节。 二、系统架构设计 技术栈组…...
AI时代新词-AI伦理(AI Ethics)
一、什么是AI伦理? AI伦理(AI Ethics)是指在人工智能(AI)的设计、开发、部署和使用过程中,涉及的道德、法律和社会问题的综合考量。它关注AI技术对人类社会、文化、价值观以及个人权利的影响,并…...
湖北理元理律师事务所债务优化服务中的“四维平衡“之道
债务问题解决需要兼顾多方利益,湖北理元理律师事务所通过独特的服务模式,在法律、经济、心理、社会四个维度建立平衡点。 一、法律维度的专业把控 合规性审查: 合同效力认定 诉讼时效核查 担保责任界定 程序合法性: 所有协…...

Git Push 失败:HTTP 413 Request Entity Too Large
Git Push 失败:HTTP 413 Request Entity Too Large 问题排查 在使用 Git 推送包含较大编译产物的项目时,你是否遇到过 HTTP 413 Request Entity Too Large 错误?这通常并不是 Git 的问题,而是 Web 服务器(如 Nginx&am…...

第10章 网络与信息安全基础知识
网络概述 多模光纤的特点:成本低,宽芯线,聚光好,耗散大,低效,用于低速度、短距离的通信。 单模光纤的特点:成本高,窄芯线,需要激光源,耗散小,高效…...
GO语言学习(九)
GO语言学习(九) 上一期我们了解了实现web的工作中极为重要的net/http抱的细节讲解,大家学会了实现web开发的一些底层基础知识,在这一期我来为大家讲解一下web工作的一个重要方法,:使用数据库,现…...

go 访问 sftp 服务 github.com/pkg/sftp 的使用踩坑,连接未关闭(含 sftp 服务测试环境搭建)
前言 最近在使用 sftp 服务时,被告知发起了海量的连接,直接把服务器搞崩,ip 被封了。 这是啥情况? golang 写的代码,我就正常的访问 sftp 服务,连接使用过后也都关闭了,咋会出现连接一直连着…...

Linux多线程(二)之进程vs线程
文章目录 Linux进程VS线程进程和线程进程的多个线程共享关于进程线程的问题 重谈地址空间Linux线程周边的概念 Linux进程VS线程 进程和线程 进程是资源分配的基本单位(进程是承担分配系统资源的基本实体) 执行流也是资源!线程是进程内部的执…...
【MogDB】测试 ubuntu server 22.04 LTS 安装mogdb 5.0.11
测试 ubuntu server 22.04 LTS 安装mogdb 5.0.11 使用的操作系统镜像是 https://releases.ubuntu.com/22.04/ubuntu-22.04.5-live-server-amd64.iso 装好操作系统后,把root登录打开了,方便后续操作。 测试过程 使用官方命令在线安装ptk rootubuntu22…...
AI时代新词-数字孪生(Digital Twin)
一、什么是数字孪生(Digital Twin)? 数字孪生(Digital Twin)是一种通过创建物理实体的虚拟副本,并利用数据和算法来模拟、分析和优化物理实体的性能和行为的技术。数字孪生结合了物联网(IoT&am…...

【HW系列】—web常规漏洞(文件上传漏洞)
文章目录 一、简介二、危害三、文件检测方式分类四、判断文件检测方式五、文件上传绕过技术六、漏洞防御措施 一、简介 文件上传漏洞是指Web应用程序在处理用户上传文件时,未对文件类型、内容、路径等进行严格校验和限制,导致攻击者可上传恶意文件&…...

如何实现 C/C++ 与 Python 的通信
C/C 与 Python 的通信可以通过多种方式实现,如使用 C API、Ctypes、Cython、SWIG、Python.h 或基于共享库的调用等。其中,使用 Ctypes 方式最为简便,适合快速调用已有的 C 函数库。例如,通过将 C 代码编译为动态链接库(…...
python炸鱼船
import pygame, random # 加载库 from pygame.locals import * pygame.init() pygame.display.set_caption("炸渔船") canvas pygame.display.set_mode((700, 500)) bgpygame.image.load("bg.png") bgpygame.transform.scale(bg,(700,500))class Hero(py…...
使用AutoKeras2.0的AutoModel进行结构化数据回归预测
1、First of All: Read The Fucking Source Code import autokeras as ak import numpy as np from sklearn.model_selection import train_test_split from sklearn.metrics import mean_squared_error# 生成数据集 np.random.seed(42) x np.random.rand(1000, 10) # 生成1…...

好用但不常用的Git配置
参考文章 文章目录 tag标签分支新仓库默认分支推送 代码合并冲突处理默认diff算法 tag标签 默认是以字母顺序排序,这会导致一些问题,比如0.5.101排在0.5.1000之后。为了解决这个问题,我们可以把默认排序改为数值排序 git config --global t…...

ULVAC VWR-400M/ERH 真空蒸发器 Compact Vacuum Evaporator DEPOX (VWR-400M/ERH)
ULVAC VWR-400M/ERH 真空蒸发器 Compact Vacuum Evaporator DEPOX (VWR-400M/ERH)...
P1068 [NOIP 2009 普及组] 分数线划定
题目描述 世博会志愿者的选拔工作正在 A 市如火如荼的进行。为了选拔最合适的人才,A 市对所有报名的选手进行了笔试,笔试分数达到面试分数线的选手方可进入面试。面试分数线根据计划录取人数的 150% 划定,即如果计划录取 m 名志愿者…...

PPT连同备注页(演讲者模式)一块转为PDF
首先,进入创建PDF/XPS: 然后进入选项: 发布选项-发布内容里选备注页: 导出的原始结果是这样的: 这个时候裁剪一下,范围为所有页面: 最终结果: 如果导出不选“备注页”而是只勾选“包…...
第三十二天打卡
作业:参考pdpbox官方文档中的其他类,绘制相应的图,任选即可 1. 安装并导入库 确保安装与文档版本一致的 pdpbox(此处以 0.3.0 为例): bash 复制 下载 pip install pdpbox0.3.0 导入所需库:…...

项目三 - 任务8:实现词频统计功能
本项目旨在实现一个词频统计功能,通过读取文本文件并利用Java编程技巧处理和分析文本数据。首先,使用BufferedReader逐行读取文件内容,然后通过String.split(" ")方法将每行文本分割成单词数组。接下来,采用HashMap来存…...
MongoDB 快速整合 SpringBoot 示例
1.添加依赖<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spr…...
2025.05.22-得物春招机考真题解析-第二题
📌 点击直达笔试专栏 👉《大厂笔试突围》 💻 春秋招笔试突围在线OJ 👉 笔试突围OJ 02. 魔法书页重排 问题描述 A先生是一位魔法师,他有一本古老的魔法书,书中有 n n n 页,每页都刻有一个魔…...

ollama list模型列表获取 接口代码
ollama list模型列表获取 接口代码 curl http://localhost:11434/v1/modelscoding package hcx.ollama;/*** ClassName DockerOllamaList* Description TODO* Author dell* Date 2025/5/26 11:31* Version 1.0**/import java.io.BufferedReader; import java.io.InputStreamR…...

OPC Client第5讲(wxwidgets):初始界面的事件处理;按照配置文件初始化界面的内容
接上一讲,即实现下述界面的事件处理代码;并且按照配置文件初始化界面的内容(三、) 事件处理的基础知识,见下述链接五、 OPC Client第3讲(wxwidgets):wxFormBuilder;基础…...
什么是BFC,如何触发BFC,BFC有什么特性?
理解 BFC指的是块级格式化上下文,处于BFC内部的盒子与外界互不影响 触发条件 position:absolute/fixed都会产生bfcdisplay:inline-block,table,flex等float:left/right 浮动也会产生bfchtml根元素也是bfc bfc的特性 属于同一个BFC下的盒子会垂直排列属于同一个BFC下的两个…...
python做题日记(9)
第二十一题 第二十一题是合并两个有序链表,合并后的链表仍然需要保持有序,因为在合并之前已经是两个有序链表,因此在合并时只需要遍历比较两个链表中的下一结点数值,将其中较小的一个结点添加到新的列表中。如果有任何一个链表已经…...
Leetcode 3557. Find Maximum Number of Non Intersecting Substrings
Leetcode 3557. Find Maximum Number of Non Intersecting Substrings 1. 解题思路2. 代码实现 题目链接:3557. Find Maximum Number of Non Intersecting Substrings 1. 解题思路 这一题就是一个比较直接的动态规划的题目,我们只需要考察每一个位是否…...

【C++进阶篇】初识哈希
哈希表深度剖析:原理、冲突解决与C容器实战 一. 哈希1.1 哈希概念1.2 哈希思想1.3 常见的哈希函数1.3.1 直接定址法1.3.2 除留余数法1.3.3 乘法散列法(了解)1.3.4 平方取中法(了解) 1.4 哈希冲突1.4.1 冲突原因1.4.2 解…...

Spring Boot——自动配置
目录 1.bean加载方式 1.1XML方式声明bean 1.2 xml 注解方式声明bean 1.3通过Configuration和Bean 1.4使用Import注解 1.5使用上下文对象在容器初始化完毕后注入bean 1.6使用ImportSelector接口 1.7实现ImportBeanDefinitionRegistrar接口 1.8bean加载方式(…...