2024-10-13-B fd 重定向 缓冲区

news2025/1/17 5:54:30

1   一切皆文件

1.1   虚拟文件系统

在系统层面,做了一层软件的封装,struct file 里有操作表(即函数指针的集合),可以调用底层的读写方法。虚拟文件系统(VFS)是一种神奇的抽象,它使得 “一切皆文件” 哲学在 Linux 中成为了可能。 (类比C++多态)

1.2   为何C/C++喜欢做封装

(1) 方便用户操作 

以“文本写入 vs 二进制写入”举例,在操作系统层面全是二进制,语言层面进行转化变为文本

(2) 提高语言的可移植性

如果不是Linux而是其他操作系统呢?C库函数 ---> 系统调用;FILE ---> fd(源代码编译成不同版本的库)

封装可以“屏蔽差异”

1.3   文件内核缓冲区

写入:

打开一个 myfile 文件,创建对应的 struct file,里面包含操作表和文件内核缓冲区address_space,write() (拷贝函数,把数据从用户拷贝至内核)把要写入的内容拷贝至文件的内核缓冲区,如果需要的话,可通过file->ops->write()将数据刷新到文件中(由OS自主决定)。

空文件写入,拷贝刷新即可;修改的本质,是先读取再写入。

为何有缓冲区?因为外设比较慢,缓冲区的存在可以变相提高IO效率。

一个进程,能在PCB中找到file对象,通过file对象,既能找到文件的操作表,又能找到文件对应的属性集,还能找到文件对应的文件内核缓冲区。

1.4   重定向

    close(0);
	int fd1 = open("return_test1.txt", O_WRONLY | O_CREAT | O_APPEND, 0666);
	int fd2 = open("return_test2.txt", O_WRONLY | O_CREAT | O_APPEND, 0666);
	int fd3 = open("return_test3.txt", O_WRONLY | O_CREAT | O_APPEND, 0666);
	int fd4 = open("return_test4.txt", O_WRONLY | O_CREAT | O_APPEND, 0666);

./ofi
fd1 of open(): 0
fd2 of open(): 3
fd3 of open(): 4
fd4 of open(): 5

进程打开文件,需要给文件分配新的fd时,fd的分配规则是以最小的且没有被使用的为优先

 重定向:把 fd_array 中特定下标对应的元素替换后,如close(1),上层不知道(printf->stdout->fileno=1),本来往显示器文件写入的变为了往新的文件写入。

系统调用:int dup2(int oldfd, int newfd)
dup2() makes newfd be the copy of oldfd, closing newfd if necessary

如果要做输出重定向,可以把文件的地址(fd)覆盖到 fd_array[1] 中,即 dup2(fd, 1)
(联想记忆:fd活得久,就old)

int fd = open("log.txt", O_CREAT | O_WRONLY | O_TRUNC, 0666);
printf("HELLO FD: %d\n", fd);
fprintf(stdout, "HELLO FD: %d\n", fd);
fputs("HELLO LINUX\n", stdout);
const char *msg = "hello fwrite\n";
fwrite(msg, 1, strlen(msg), stdout);

往显示器里写入

HELLO FD: 3
HELLO FD: 3
HELLO LINUX
hello fwrite

使用 dup2(fd, 1);

$ cat log.txt 
HELLO FD: 3
HELLO FD: 3
HELLO LINUX
hello fwrite

1.4.1    命令行中重定向内容的解析

"ls -a -l -n" < hello.txt

"ls -a -l -n" > hello.txt

"ls -a -l -n" >> hello.txt

//全局变量(重定向相关)
#define NoRedir 0
#define InRedir 1
#define OutRedir 2
#define AppRedir 3

int redirtype = NoRedir;
char *filename = nullptr;
//过滤空格
#define TrimSpace(pos) do{\ //while(0)的作用是形成代码块,可以整体替换
        while(isspace(*pos)){\
                pos++;\
        }\
}while(0)
bool ParseCommandLine(char commandline_buffer[], int len){
//......

        //重定向
        redir = NoRedir;
        filename = nullptr;

        //"ls -a -l -n" > file.txt
        int end = len - 1;
        while(end >= 0){
                if(commandline_buffer[end] == '<'){
                        redir = InRedir;
                        filename = &commandline_buffer[end] + 1;
                        TrimSpace(filename);
                        commandline_buffer[end] = 0;
                        break;
                }else if(commandline_buffer[end] == '>'){
                        if(commandline_buffer[end - 1] == '>'){
                                redir = AppRedir;
                                commandline_buffer[end] = 0;
                                commandline_buffer[end - 1] = 0;
                                filename = &commandline_buffer[end] + 1;
                                TrimSpace(filename);
                                break;
                        }else{
                                redir = OutRedir;
                                commandline_buffer[end] = 0;
                                filename = &commandline_buffer[end] + 1;
                                TrimSpace(filename);
                                break;
                        }
                }else{
                        end--;
                }
        }
//......
}

2   总结

(1)文件描述符的概念,文件也是要被管理的(= 内容 + 属性),分为未打开的和被打开的
(2)标准输入输出错误之间的关系,以及系统调用接口open, close, read, write,文件流封装的底层一定有文件描述符
(3)文件描述符分配规则、012,重定向概念、原理、操作、如何进行
(4)内核角度理解“一切皆文件”,通过 struct file 对象和函数指针表屏蔽差异
(5)一个进程有自己的PCB,也要有自己打开的文件描述符表,还要有自己打开的工作文件,每个文件都要配备操作表、属性集和内核级缓冲区

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

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

相关文章

调整数组顺序使奇数位于偶数前面

题目 输入一个整数数组&#xff0c;调整数组中数字的顺序&#xff0c;使得所有奇数位于数组的前半部分&#xff0c;所有偶数位于数组的后半部分。要求时间复杂度为O(n) 解法 双指针i和j 指针i起点是数组起点&#xff0c;当i检测到偶数时停下。j的起点时数组终点&#xff0c;…

如何使用 Docker Compose 安装 Memos 自托管笔记应用

简介 Memos是一个自托管的开源笔记应用程序&#xff0c;专为个人组织和信息管理而设计。它允许用户高效地创建、存储和管理笔记&#xff0c;提供如Markdown支持、用户友好的界面和注重隐私的设计等功能。Memos可以在各种平台上运行&#xff0c;但使用Docker Compose可以简化部…

详解:HTTP/HTTPS协议

HTTP协议 一.HTTP是什么 HTTP&#xff0c;全称超文本传输协议&#xff0c;是一种用于分布式、协作式、超媒体信息系统的应用层协议。HTTP往往是基于传输层TCP协议实现的&#xff0c;采用的一问一答的模式&#xff0c;即发一个请求&#xff0c;返回一个响应。 Q&#xff1a;什…

小程序项目的基本组成结构

分类介绍 项目根目录下的文件及文件夹 pages文件夹 用来存放所有小程序的页面&#xff0c;其中每个页面都由4个基本文件组成&#xff0c;它们分别是&#xff1a; .js文件&#xff1a;页面的脚本文件&#xff0c;用于存放页面的数据、事件处理函数等 .json文件&#xff1a;…

【uni-app 微信小程序】新版本发布提示用户进行更新

知识准备 uni.getUpdateManager文档介绍 不支持APP与H5&#xff0c;所以在使用的时候要做好平台类型的判断&#xff0c;如何判断&#xff0c;参考条件编译处理多端差异 代码参考 export const updateApp () > {const updateManager uni.getUpdateManager()updateManag…

LabVIEW断路器检测系统

随着电网技术的快速发展&#xff0c;对电力系统的可靠性和安全性要求不断提高&#xff0c;塑壳断路器作为关键的保护设备&#xff0c;其出厂前的检测非常重要。开发了一种基于LabVIEW软件平台开发的塑壳断路器智能脱扣器检测系统&#xff0c;该系统能够有效提高检测的自动化水平…

ASP.NET Core API 前后端分离跨域

环境准备 数据库&#xff1a; sqlserver 2022 后端&#xff1a; vs2022 ASP.NET Core API .net 8 前端&#xff1a; Hbuilderx bootstrap 5.3.0 jquery v3.7.1 bootstrap-table 1.23.5 完整项目代码下载地址 功能 实现 单张表 的 增 删 改 查 创建数据库和表 create data…

Mac M1 安装数据库

1. Docker下载 由于Sqlserver和达梦等数据库&#xff0c;不支持M系列的芯片&#xff0c;所以我们通过docker安装 下载并安装docker: https://www.docker.com/get-started/ 安装完成后&#xff0c;打开docker 2. SQL Server 安装 2.1 安装 打开终端&#xff0c;执行命令 doc…

进程的管理与控制

一、进程与线程 1. 进程 程序&#xff1a;是静态的&#xff0c;就是个存放在磁盘里的可执行文件&#xff0c;就是一系列的指令集合。 进程&#xff08;Process&#xff09;&#xff1a;是指计算机中已执行的程序&#xff0c;是动态的。 &#xff08;1&#xff09;进程的组成…

SQLCipher:SQLite加密工具的实用指南

本文还有配套的精品资源&#xff0c;点击获取 简介&#xff1a;SQLCipher是一个开源工具&#xff0c;用于为SQLite数据库提供透明的数据加密功能&#xff0c;确保数据安全。其工作原理是通过在SQLite的API上增加一层加密层&#xff0c;并使用AES加密算法确保数据在未授权访问…

如何将 JavaWeb 项目部署到云服务器

1. 搭建 Java 部署环境 接下来以 Ubuntu 来进行演示 1.1. apt 包管理工具 apt 就相当于手机上的应用市场 列出所有软件包&#xff1a;apt list 这个命令输出所有包的列表&#xff0c;内容比较多&#xff0c;可以使用 grep 命令过滤输出&#xff1a;apt list |grep "jd…

自动驾驶算法——卡尔曼滤波器平滑感知车道线参数【C++代码实现】

1.算法原理 在工程实践中,由于感知识别到的车道线偶尔存在较大的跳变,导致后端控制算法计算出的控制角度也存在较大的跳变,所以我们需要对感知输入的车道线系数进行平滑处理。 已知卡尔曼滤波算法主要分为以下几大步骤: 感知将车道线以三次螺旋曲线方程 y = c 0 + c 1 x +…

用python替换和循环插入excel的内容

用python替换和循环插入excel的内容 目的&#xff1a; 1.有一个word模板和一个有数据的excel表格 2.需要将excel中的数据经过更改成需要的字符串插入word段落中 3.更改word中的字符串 4.写一个现阶段可以用的程序&#xff0c;并用作以后更新迭代复用。 过程&#xff1a; …

UE5基本数据类型

bool: 表示布尔值&#xff0c;只有两个取值&#xff1a;true 或 false&#xff0c;用于表示逻辑条件。int8: 表示 8 位的有符号整数&#xff0c;范围是 −128−128 到 127127。uint8: 表示 8 位的无符号整数&#xff0c;范围是 00 到 255255。int16: 表示 16 位的有符号整数&am…

【Unity高级】在编辑器中如何让物体围绕一个点旋转固定角度

本文介绍如何在编辑器里让物体围绕一个点旋转固定角度&#xff0c;比如上图里的Cube是围绕白色圆盘的中心旋转45度的。 目标&#xff1a; 创建一个在 Unity 编辑器中使用的旋转工具&#xff0c;使开发者能够在编辑模式下快速旋转一个物体。 实现思路&#xff1a; 编辑模式下…

深度学习:从入门到精通的全面学习路径

摘要&#xff1a; 本文详细阐述了深度学习从入门到精通的系统学习路线。从基础数学与编程知识的夯实&#xff0c;到深度学习核心技术栈的深入掌握&#xff0c;包括 TensorFlow 与 PyTorch 等框架的应用&#xff1b;再到各类主流深度学习算法的原理学习与实践&#xff0c;涵盖神…

CC2530传感器应用实例

1.CC2530流水灯实验 //基于CC2530微控制器的程序&#xff0c;用于控制三个LED灯的闪烁。#include <ioCC2530.h>#define uint unsigned int #define uchar unsigned charuint代表无符号整型&#xff0c;uchar代表无符号字符型。#define LED1 P1_0 #define LED2 P1_1 #defi…

深度和法线纹理

屏幕后期处理效果的基本原理就是当游戏画面渲染完毕后通过获取到该画面的信息进行额外的效果处理 之前的边缘检测、高斯模糊、Bloom、运动模糊等效果都是基于获取当前屏幕图像中的像素信息进行后期处理的 如果仅仅根据像素信息来进行一些效果处理&#xff0c;存在以下问题&…

Oracle之表空间迁移

问题背景&#xff1a;一个数据表随着时间的累积&#xff0c;导致所在表空间占用很高&#xff0c;里面历史数据可以清除&#xff0c;保留近2个月数据即可 首先通过delete删除了2个月以前的数据。 按网上的教程进行空间压缩&#xff0c;以下sql在表所在用户执行: -- 允许表重新…

非父子通信(扩展)-- event bus 事件总线

创建一个空实例Bus&#xff0c; export default 导出Bus 过程:由A组件对Bus组件进行监听&#xff0c;B组件触发Bus对应的事件&#xff0c;由于A组件进行监听&#xff0c;触发事件之后就会进行A组件的回调&#xff0c;那么就可以将消息发送给A了 在src文件夹下新建utils文件夹&a…