[Linux] 逐层深入理解文件系统 (2)—— 文件重定向
标题:[Linux] 逐层深入理解文件系统 (2)—— 文件重定向
个人主页@水墨不写bug
(图片来源于网络)
目录
一、文件的读取和写入
二、文件重定向的本质
1.手动模拟重定向的过程——把标准输出重定向到redir.txt
2.重定向函数dup2
3.命令行的重定向指令操作
四、缓冲区的刷新策略
正文开始:
一、文件的读取和写入
在深入理解文件系统(1)中,我们深入了解了文件的打开与关闭:操作系统通过文件描述符fd来对文件进行管理操作。此外,我们知道了文件的系统调用级别的打开方式,但是我们还没有了解如何读写文件的内容。
文件的写入同样有对应的系统调用:
参数列表:
fd:想要写入的文件的对应的文件描述符(对打开文件后会得到对应的文件描述符)
*buf:这是一个我们定义的数组,是一个缓冲区。
count:写入的字节数
返回值:
成功,返回写入的字节数;失败,返回-1,并设置错误码。
文件的读取的系统调用:
参数列表:
fd:想要读取的文件的对应的文件描述符
*buf:把文件的内容读取到这个数组中。
count:读取的字节数。
返回值:
成功,返回读取的字节数;失败,返回-1,设置错误码。
二、文件重定向的本质
文件重定向的本质是在内核中改变文件描述符表的特定下标,和上层的语言层面的无关。
1.手动模拟重定向的过程——把标准输出重定向到redir.txt
1)使用系统调用close关闭 标准输出(fd==1的文件)
2)使用系统调用open打开redir.txt文件
这个时候向标准输出打印信息就会被重定向到redir.txt文件中。
底层原理:
首先我们关闭了标准输出(文件fd==1的文件),文件描述符标的下标1的这位置就被空出来了,由于文件描述符的分配规则是从小到大来分配的,当我们打开一个新的文件(redir.txt)这个文件的fd就会被分配为1。
我们向标准输出写入,本质是向文件描述符表下标1的位置对应的内核级缓冲区写入,由于redir.txt分配到了1这个位置,所以向原来的标准输出的缓冲区写入,就是向redir.txt的缓冲区写入。
这样就实现了文件的重定向。
关闭标准输出后打开redir.txt:

2.重定向函数dup2
函数原型 :
简单总结:
函数作用:让newfd对应的内容成为oldfd对应的内容的拷贝,本质是文件描述符下标所对应的内容的拷贝,并在结束的时候首先关闭newfd。
注意:
1)oldfd不是一个有效的fd,则调用失败, newfd不会被关闭。
2)oldfd是有效的fd,但是newfd和oldfd对应同一个文件,dup2函数不做任何事。
dup2系统调用函数的意义在于可以让我们的重定向操作更加方便比如如果我们还是想要把标准输出重定向到redir.txt文件,那么只需要调用一个系统调用函数即可:
int fd1 = open("redir.txt",O_CREAT | O_WDONLY);dup2(fd1,1);//这样就实现了把标准输出重定向到fd1
3.命令行的重定向指令操作
我们写出这样的一个代码:
#include<stdio.h>
int main()
{fprintf(stdout,"hello stdout\n");fprintf(stderr,"hello stderr\n");return 0;
}
编译完运行:
发现标准输出和标准错误都是显示器,这符合预期。
对一个项目,我们可以把运行结果重定向到不同的日志文件中,方便后续维护:

上面的操作是把运行结果(向显示器输出重定向到两个文件中):
标准输出重定向到ok.txt;
标准错误重定向到err.txt。
如果不加fd直接重定向,会仅仅把标准输出重定向:
标准错误仍被打印到显示器。
如果想把标准输出和标准错误重定向到一个文件,需要:

四、缓冲区的刷新策略
在之前,我们知道在文件IO中 缓冲区存在两个,一个是C语言层面的缓冲区,一个是系统内核级缓冲区,但是我们并不了解缓冲区究竟是什么。
是什么:缓冲区就是一段连续的内存空间。
为什么:将系统调用和与硬件交互解耦,将C语言函数调用与系统调用解耦;提高刷新效率,从而在整体上提高IO效率,为用户提供高效的IO体验。
怎么办:这就需要谈到不同的刷新策略问题了。
对于不同的文件,缓冲区的刷新策略不同。常见刷新策略有如下几种:
1)立刻刷新。比如调用fflush(stdout)(立刻刷新语言缓冲区) , fsync(fd)(立刻刷新系统缓冲区)等。
2)行刷新。显示器,因为显示器需要照顾用户查看习惯。
3) 全缓冲,缓冲区写满才刷新。比如普通文件。
此外,对于特殊情况也会进行缓冲区刷新:
a)进程退出,系统自动刷新缓冲区
在了解了缓冲区刷新策略之后,我们看看下面这样的场景:
#include<stdio.h>
#include<string.h>
#include<unistd.h>int main()
{printf("hello printf\n");fprintf(stdout,"hello fprintf\n");const char* msg = "hello write\n";write(1,msg,strlen(msg));return 0;
}
编译成功运行结果:

当我们重定向到log.txt,并打印出来:
发现顺序不一样了,原因在于缓冲区向文件写入时刷新策略发生了变化:
对一次是向显示器写入,刷新策略是按行刷新,由于三次打印有带有换行符,所以是按照代码的顺序打印输出。
第二次是向文件写入,策略是全缓冲,所以尽管带有换行符,前两次写入都是暂时写入到了C语言级别的缓冲区内了,没有立刻被刷新到内核级缓冲区内。但是write是系统调用,直接刷新到了内核级缓冲区,所以最先被写入文件,后来在进程结束前,语言级缓冲区刷新到内核级,再被刷新到磁盘的文件中。
这个场景还有一个变式:
#include<stdio.h>
#include<string.h>
#include<unistd.h>
#include<sys/types.h>int main()
{printf("hello printf\n");fprintf(stdout,"hello fprintf\n");const char* msg = "hello write\n";write(1,msg,strlen(msg));fork();return 0;
}
运行后直接输出到显示器:

在意料之内。
但是重定向到log.txt文件并cat打印出来:

发现了不对劲,其实造成这样的现象本质也是缓冲区刷新策略的变化导致的。
write是系统调用,会直接刷新到内核级缓冲区。但是这个时候前两个语句已经被执行了,但是数据还存在于语言缓冲区内。这个时候fork创建了一个子进程,子进程的数据和父进程相同,在进程结束之前,两个进程都刷新了自己的语言级缓冲区,导致前两个打印语句被执行了两次!
完~
未经作者同意禁止转载
相关文章:
[Linux] 逐层深入理解文件系统 (2)—— 文件重定向
标题:[Linux] 逐层深入理解文件系统 (2)—— 文件重定向 个人主页水墨不写bug (图片来源于网络) 目录 一、文件的读取和写入 二、文件重定向的本质 1.手动模拟重定向的过程——把标准输出重定向到redir.txt 2.重定向…...
html+css+js实现Badge 标记
实现效果: 代码实现: <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Badge…...
纯css 轮播图片,鼠标移入暂停 移除继续
核心 滚动: animation: 动画名称 20s linear infinite normal;停止: animation: 动画名称 20s linear infinite paused; 完整例子: html: <div class"carousel-wrapper"><div class"carousel"><div cl…...
iOS GCD的基本使用
一:什么是GCD GCD的全程是:Grand Central Dispatch, 直白的用汉语翻译就是:厉害的中枢调度器. GCD 是iOS 的多线程技术的实现方案,但是它并不是多线程技术,它是“并发解决技术”,是苹果公司研发的,会自动管理线程(这一段定义有点拗口,简单了解就行) GCD会自动管理线程的生命…...
如何设计开发RTSP直播播放器?
技术背景 我们在对接RTSP直播播放器相关技术诉求的时候,好多开发者,除了选用成熟的RTSP播放器外,还想知其然知其所以然,对RTSP播放器的整体开发有个基础的了解,方便方案之作和技术延伸。本文抛砖引玉,做个…...
Java基础系列-一文搞懂自定义排序
java自定义排序 自定义排序的理解: 我们首先看需求:一个二维数组 [[1,3],[8,10],[15,18],[2,6]] 我们的需求是根据集合(二维数组取出来的数据) 左边小的左边这种方式排序 例如1<8 排序方式就是[1,3],[8,10] 此时我们就需…...
扫普通链接二维码打开小程序
1. 2.新增规则(注意下载文件到跟目录下,需要建个文件夹放下载的校验文件) 3.发布 ps:发布后,只能访问正式版本。体验版本如果加了 测试链接http://xxx/xsc/10 那么http://xxx/xsc/aa.....应该都能访问 例如aa101 aa…...
计算机储存与分区
Disk partitioning 盘分区是在辅助储存上创建一个或多个区域,以便可以单独管理每个区域。而这些区域称为分区(partition)。这通常是在为新盘选择分区方案后,需要做的事。 MBR and GPT 分区方案(分区表)有…...
OpenCV之换脸技术:一场面部识别的奇妙之旅
在这个数字化与智能化并进的时代,图像处理技术日益成为连接现实与虚拟世界的桥梁。其中,换脸技术作为一项颇受欢迎且富有挑战性的应用,不仅让人惊叹于技术的魔力,更在娱乐、影视制作等领域展现了无限可能。今天,我们就…...
Linux学习笔记9 文件系统的基础
一、查看文件组织结构 Linux中一切都是文件。 Linux和Win的文件系统不是一个结构,Linux存在的根目录是所有目录的起点。 所有的存储空间和设备共享一个根目录,不同的磁盘块和分区挂载在其下,成为某个子目录的子目录,甚至设备也挂…...
Android OpenGL粒子特效
在本篇,我们将开启一个新的项目,探索粒子的世界。粒子是一种基本的图形元素,它们通常被表示为一组点。通过巧妙地组合一些基础的物理效果,我们能够创造出许多令人惊叹的视觉效果。想象一下,我们可以模拟一个水滴从喷泉…...
5 -《本地部署开源大模型》在Ubuntu 22.04系统下ChatGLM3-6B高效微调实战
在Ubuntu 22.04系统下ChatGLM3-6B高效微调实战 无论是在单机单卡(一台机器上只有一块GPU)还是单机多卡(一台机器上有多块GPU)的硬件配置上启动ChatGLM3-6B模型,其前置环境配置和项目文件是相同的。如果大家对配置过程还…...
dpkg:错误:另外一个进程已经为dpkg前端锁加锁
一、 问题描述 在新装ubuntu系统时,我们常常会遇见dpkg的错误,dpkg:错误:另外一个进程已经为dpkg前端锁加锁,如下图。 二、问题解决 方法一 先执行sudo rm /var/lib/dpkg/lock-frontend然后再继续安装软件包,如果出现问题dpkg:…...
基于SSM服装定制系统的设计
管理员账户功能包括:系统首页,个人中心,用户管理,服装类型管理,服装信息管理,服装定制管理,留言反馈,系统管理 前台账号功能包括:系统首页,个人中心…...
RK3588开发笔记-usb3.0 xhci-hcd控制器挂死问题解决
目录 前言 一、问题现象 二、问题分析 三、问题排查 总结 前言 在使用 RK3588 芯片进行开发的过程中,我遇到了 USB 3.0 xHCI-HCD 控制器外接5G通讯模块偶尔挂死的问题。这个问题导致 USB 设备失去响应,且不能恢复,需要重启整个系统才能恢复使用,针对该问题进行大量测试以…...
深入解析TCP/IP协议:网络通信的基石
1. 引言 TCP/IP 协议是现代计算机网络的核心,它为互联网上的设备提供了通信的基础。在网络通信中,TCP/IP 协议栈是无处不在的,无论是个人设备的浏览器请求,还是大型分布式系统的内部通信,都依赖于它的稳定、高效与可靠…...
基于微信小程序的汽车预约维修系统(lw+演示+源码+运行)
基于微信小程序的汽车预约维修系统 摘要 随着信息技术在管理上越来越深入而广泛的应用,管理信息系统的实施在技术上已逐步成熟。本文介绍了基于微信小程序的汽车预约维修系统的开发全过程。通过分析基于微信小程序的汽车预约维修系统管理的不足,创建了…...
wifi、热点密码破解 - python
乐子脚本,有点小慢,试过多线程,系统 wifi 连接太慢了,需要时间确认,多线程的话系统根本反应不过来。 也就可以试试破解别人的热点,一般都是 123456 这样的傻鸟口令 # coding:utf-8 import pywifi from pyw…...
bean的实例化2024年10月17日
跟不上为基础 1.你的java学习路线 2. 3.课程 注解的装配 contoller调用service用的是注解装配...
告别ELK,APO提供基于ClickHouse开箱即用的高效日志方案——APO 0.6.0发布
ELK一直是日志领域的主流产品,但是ElasticSearch的成本很高,查询效果随着数据量的增加越来越慢。业界已经有很多公司,比如滴滴、B站、Uber、Cloudflare都已经使用ClickHose作为ElasticSearch的替代品,都取得了不错的效果ÿ…...
利用最小二乘法找圆心和半径
#include <iostream> #include <vector> #include <cmath> #include <Eigen/Dense> // 需安装Eigen库用于矩阵运算 // 定义点结构 struct Point { double x, y; Point(double x_, double y_) : x(x_), y(y_) {} }; // 最小二乘法求圆心和半径 …...
【OSG学习笔记】Day 18: 碰撞检测与物理交互
物理引擎(Physics Engine) 物理引擎 是一种通过计算机模拟物理规律(如力学、碰撞、重力、流体动力学等)的软件工具或库。 它的核心目标是在虚拟环境中逼真地模拟物体的运动和交互,广泛应用于 游戏开发、动画制作、虚…...
ffmpeg(四):滤镜命令
FFmpeg 的滤镜命令是用于音视频处理中的强大工具,可以完成剪裁、缩放、加水印、调色、合成、旋转、模糊、叠加字幕等复杂的操作。其核心语法格式一般如下: ffmpeg -i input.mp4 -vf "滤镜参数" output.mp4或者带音频滤镜: ffmpeg…...
跨链模式:多链互操作架构与性能扩展方案
跨链模式:多链互操作架构与性能扩展方案 ——构建下一代区块链互联网的技术基石 一、跨链架构的核心范式演进 1. 分层协议栈:模块化解耦设计 现代跨链系统采用分层协议栈实现灵活扩展(H2Cross架构): 适配层…...
DIY|Mac 搭建 ESP-IDF 开发环境及编译小智 AI
前一阵子在百度 AI 开发者大会上,看到基于小智 AI DIY 玩具的演示,感觉有点意思,想着自己也来试试。 如果只是想烧录现成的固件,乐鑫官方除了提供了 Windows 版本的 Flash 下载工具 之外,还提供了基于网页版的 ESP LA…...
ETLCloud可能遇到的问题有哪些?常见坑位解析
数据集成平台ETLCloud,主要用于支持数据的抽取(Extract)、转换(Transform)和加载(Load)过程。提供了一个简洁直观的界面,以便用户可以在不同的数据源之间轻松地进行数据迁移和转换。…...
论文浅尝 | 基于判别指令微调生成式大语言模型的知识图谱补全方法(ISWC2024)
笔记整理:刘治强,浙江大学硕士生,研究方向为知识图谱表示学习,大语言模型 论文链接:http://arxiv.org/abs/2407.16127 发表会议:ISWC 2024 1. 动机 传统的知识图谱补全(KGC)模型通过…...
解决本地部署 SmolVLM2 大语言模型运行 flash-attn 报错
出现的问题 安装 flash-attn 会一直卡在 build 那一步或者运行报错 解决办法 是因为你安装的 flash-attn 版本没有对应上,所以报错,到 https://github.com/Dao-AILab/flash-attention/releases 下载对应版本,cu、torch、cp 的版本一定要对…...
NLP学习路线图(二十三):长短期记忆网络(LSTM)
在自然语言处理(NLP)领域,我们时刻面临着处理序列数据的核心挑战。无论是理解句子的结构、分析文本的情感,还是实现语言的翻译,都需要模型能够捕捉词语之间依时序产生的复杂依赖关系。传统的神经网络结构在处理这种序列依赖时显得力不从心,而循环神经网络(RNN) 曾被视为…...
Angular微前端架构:Module Federation + ngx-build-plus (Webpack)
以下是一个完整的 Angular 微前端示例,其中使用的是 Module Federation 和 npx-build-plus 实现了主应用(Shell)与子应用(Remote)的集成。 🛠️ 项目结构 angular-mf/ ├── shell-app/ # 主应用&…...




简单总结: